From 02f39862fe94eb9e8836f3b35c0e05c73c625469 Mon Sep 17 00:00:00 2001
From: Hosted Weblate
Date: Thu, 25 Dec 2025 05:00:21 +0100
Subject: [PATCH 01/64] Translated using Weblate (Ukrainian)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Currently translated at 2.9% (3 of 103 strings)
Added translation using Weblate (Ukrainian)
Added translation using Weblate (Japanese)
Co-authored-by: Hosted Weblate
Co-authored-by: Zilong Liu <2821624044@qq.com>
Co-authored-by: Руслан Пузич
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/uk/
Translation: Nezha/User frontend
---
src/locales/ja/translation.json | 1 +
src/locales/uk/translation.json | 7 +++++++
2 files changed, 8 insertions(+)
create mode 100644 src/locales/ja/translation.json
create mode 100644 src/locales/uk/translation.json
diff --git a/src/locales/ja/translation.json b/src/locales/ja/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/src/locales/ja/translation.json
@@ -0,0 +1 @@
+{}
diff --git a/src/locales/uk/translation.json b/src/locales/uk/translation.json
new file mode 100644
index 0000000..08d03ed
--- /dev/null
+++ b/src/locales/uk/translation.json
@@ -0,0 +1,7 @@
+{
+ "nezha": "Nezha Моніторинг",
+ "theme": {
+ "light": "Світла тема",
+ "dark": "Темна тема"
+ }
+}
From d931cde72241d1b1a10aaa8081b97ff2ef80dfec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9F=D1=83=D0=B7?=
=?UTF-8?q?=D0=B8=D1=87?=
Date: Tue, 30 Dec 2025 05:04:14 +0100
Subject: [PATCH 02/64] Translated using Weblate (Ukrainian)
Currently translated at 11.6% (12 of 103 strings)
Translation: Nezha/User frontend
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/uk/
---
src/locales/uk/translation.json | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/src/locales/uk/translation.json b/src/locales/uk/translation.json
index 08d03ed..d3b039c 100644
--- a/src/locales/uk/translation.json
+++ b/src/locales/uk/translation.json
@@ -2,6 +2,23 @@
"nezha": "Nezha Моніторинг",
"theme": {
"light": "Світла тема",
- "dark": "Темна тема"
- }
+ "dark": "Темна тема",
+ "system": "Система"
+ },
+ "NoResults": "Немає результатів",
+ "Servers": "Сервери",
+ "map": {
+ "Servers": "сервери"
+ },
+ "serverCard": {
+ "mem": "МЕМ"
+ },
+ "serverDetail": {
+ "mem": "МЕМ"
+ },
+ "serverDetailChart": {
+ "mem": "МЕМ"
+ },
+ "overview": "Огляд",
+ "dashboard": "Інформаційна панель"
}
From e399679f35ff14c89c71c0a4b25093a79f6dd235 Mon Sep 17 00:00:00 2001
From: nlimeres
Date: Mon, 16 Feb 2026 16:32:10 +0100
Subject: [PATCH 03/64] Added translation using Weblate (Galician)
---
src/locales/gl/translation.json | 1 +
1 file changed, 1 insertion(+)
create mode 100644 src/locales/gl/translation.json
diff --git a/src/locales/gl/translation.json b/src/locales/gl/translation.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/src/locales/gl/translation.json
@@ -0,0 +1 @@
+{}
From 4027c6570a8734c710aa2e7987de4bf9553a47d1 Mon Sep 17 00:00:00 2001
From: nlimeres
Date: Mon, 16 Feb 2026 16:58:16 +0100
Subject: [PATCH 04/64] Translated using Weblate (Galician)
Currently translated at 100.0% (103 of 103 strings)
Translation: Nezha/User frontend
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/gl/
---
src/locales/gl/translation.json | 138 +++++++++++++++++++++++++++++++-
1 file changed, 137 insertions(+), 1 deletion(-)
diff --git a/src/locales/gl/translation.json b/src/locales/gl/translation.json
index 0967ef4..79dec92 100644
--- a/src/locales/gl/translation.json
+++ b/src/locales/gl/translation.json
@@ -1 +1,137 @@
-{}
+{
+ "nezha": "Monitoreo Nezha",
+ "theme": {
+ "light": "Claro",
+ "dark": "Escuro",
+ "system": "Sistema"
+ },
+ "overview": "Visión xeral",
+ "dashboard": "Panel de control",
+ "login": "Inciar sesión",
+ "online": "Activo",
+ "offline": "Desconectado",
+ "whereTheTimeIs": "Onde está a hora",
+ "refreshing": "Recargando",
+ "info": {
+ "websocketConnecting": "Conectando o WebSocket",
+ "websocketConnected": "WebSocket conectado",
+ "websocketDisconnected": "WebSocket desconectado",
+ "processing": "Procesando..."
+ },
+ "serverOverview": {
+ "totalServers": "Servidores totais",
+ "onlineServers": "Servidores en liña",
+ "offlineServers": "Servidores desconectados",
+ "totalBandwidth": "Ancho de banda total",
+ "speed": "Velocidade",
+ "network": "Rede"
+ },
+ "map": {
+ "Distributions": "Os servidores están distribuidos en",
+ "Regions": "Rexións",
+ "Servers": "servidores"
+ },
+ "serverCard": {
+ "mem": "MEM",
+ "stg": "STG",
+ "days": "Dias",
+ "hours": "Horas",
+ "upload": "Subir",
+ "download": "Descargar",
+ "system": "Sistema",
+ "uptime": "Tempo activo",
+ "totalUpload": "Subir",
+ "totalDownload": "Descargar"
+ },
+ "cycleTransfer": {
+ "used": "empregado",
+ "total": "total",
+ "nextUpdate": "próxima actualización"
+ },
+ "serviceTracker": {
+ "noService": "Non hai información do servizo",
+ "uptime": "Tempo de actividade",
+ "delay": "Atraso",
+ "daysAgo": "dias atrás",
+ "today": "Hoxe",
+ "loading": "Cargando..."
+ },
+ "serverDetail": {
+ "status": "Estado",
+ "online": "Activo",
+ "days": "Días",
+ "hours": "Horas",
+ "offline": "Desconectado",
+ "unknown": "Descoñecido",
+ "uptime": "Tempo activo",
+ "version": "Versión",
+ "arch": "Arch",
+ "mem": "Mem",
+ "disk": "Disco",
+ "region": "Rexión",
+ "system": "Sistema",
+ "upload": "Subida",
+ "download": "Descarga",
+ "lastActive": "Última vez activo",
+ "temperature": "Temperatura",
+ "bootTime": "Tempo de reinicio"
+ },
+ "serverDetailChart": {
+ "process": "Proceso",
+ "disk": "Disco",
+ "mem": "Mem",
+ "swap": "Swap",
+ "upload": "Subida",
+ "download": "Descarga"
+ },
+ "footer": {
+ "themeBy": "Tema por "
+ },
+ "language": {
+ "zh-CN": "简体中文 (Chinés simplificado)",
+ "zh-TW": "繁體中文 (Chinés tradicional)",
+ "en-US": "English (Inglés)",
+ "de-DE": "Deutsch (Alemán)",
+ "es-ES": "Español",
+ "ru-RU": "Русский (Ruso)",
+ "ta-IN": "தமிழ் (Tamil)"
+ },
+ "error": {
+ "pageNotFound": "Páxina non atopada",
+ "backToHome": "Voltar áo inicio"
+ },
+ "tabSwitch": {
+ "Detail": "Detalle",
+ "Network": "Rede"
+ },
+ "monitor": {
+ "noData": "Non hai datos de monitor de servidor. Engada primeiro un monitor de servizo",
+ "avgDelay": "Latencia",
+ "monitorCount": "Servizos",
+ "packetLoss": "Pérdida de datos",
+ "clearSelections": "Limpar"
+ },
+ "pwa": {
+ "offlineReady": "Aplicación lista para traballar desconectada (offline)",
+ "newContent": "Novo contido dispoñíble",
+ "reload": "Actualizar"
+ },
+ "billingInfo": {
+ "remaining": "Restante",
+ "error": "erro",
+ "indefinite": "Indefinido",
+ "expired": "Expirado",
+ "days": "días",
+ "price": "Precio",
+ "free": "Gratis",
+ "usage-baseed": "Baseado no uso"
+ },
+ "TypeCommand": "Escribe un comando ou procura...",
+ "NoResults": "Non se atoparon resultados.",
+ "Servers": "Servidores",
+ "Shortcuts": "Atallos",
+ "ToggleLightMode": "Cambiar ao modo claro",
+ "ToggleDarkMode": "Cambiar ao modo escuro",
+ "ToggleSystemMode": "Cambiar ao determinado polo sistema",
+ "Home": "Páxina principal"
+}
From 8810ac963d103afd1ac32295e1d17a702377e787 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9F=D1=83=D0=B7?=
=?UTF-8?q?=D0=B8=D1=87?=
Date: Sat, 21 Feb 2026 11:01:23 +0100
Subject: [PATCH 05/64] Translated using Weblate (Ukrainian)
Currently translated at 50.4% (52 of 103 strings)
Translation: Nezha/User frontend
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/uk/
---
src/locales/uk/translation.json | 67 ++++++++++++++++++++++++++++-----
1 file changed, 58 insertions(+), 9 deletions(-)
diff --git a/src/locales/uk/translation.json b/src/locales/uk/translation.json
index d3b039c..b79fa7b 100644
--- a/src/locales/uk/translation.json
+++ b/src/locales/uk/translation.json
@@ -1,24 +1,73 @@
{
"nezha": "Nezha Моніторинг",
"theme": {
- "light": "Світла тема",
- "dark": "Темна тема",
- "system": "Система"
+ "light": "Світло",
+ "dark": "Темний",
+ "system": "Як в Системі"
},
- "NoResults": "Немає результатів",
+ "NoResults": "Немає результатів.",
"Servers": "Сервери",
"map": {
- "Servers": "сервери"
+ "Servers": "сервери",
+ "Distributions": "Сервери розподілені в",
+ "Regions": "Регіони"
},
"serverCard": {
- "mem": "МЕМ"
+ "mem": "МЕМ",
+ "stg": "STG",
+ "days": "Днів",
+ "hours": "Годин",
+ "upload": "Завантаження",
+ "download": "Завантажити",
+ "system": "Система",
+ "uptime": "Аптайм",
+ "totalUpload": "Завантажено",
+ "totalDownload": "Скачано"
},
"serverDetail": {
- "mem": "МЕМ"
+ "mem": "Мем",
+ "status": "Статус",
+ "online": "Online",
+ "days": "Днів",
+ "hours": "Годин",
+ "offline": "Offline",
+ "unknown": "Невідомо"
},
"serverDetailChart": {
- "mem": "МЕМ"
+ "mem": "Мем"
},
"overview": "Огляд",
- "dashboard": "Інформаційна панель"
+ "dashboard": "Інформаційна панель",
+ "online": "Онлайн",
+ "offline": "Оффлайн",
+ "whereTheTimeIs": "Де час",
+ "refreshing": "Оновлення",
+ "info": {
+ "websocketConnecting": "WebSocket з'єднання",
+ "websocketConnected": "WebSocket з'єднано",
+ "websocketDisconnected": "WebSocket відключено",
+ "processing": "Обробка..."
+ },
+ "serverOverview": {
+ "totalServers": "Всього Серверів",
+ "onlineServers": "Сервери в мережі",
+ "offlineServers": "Сервери не в мережі",
+ "totalBandwidth": "Загальна пропускна здатність",
+ "speed": "Швидкість",
+ "network": "Мережа"
+ },
+ "cycleTransfer": {
+ "used": "використано",
+ "total": "всього",
+ "nextUpdate": "наступне оновлення"
+ },
+ "serviceTracker": {
+ "noService": "Немає даних про сервіс",
+ "uptime": "Аптайм",
+ "delay": "Затримка",
+ "daysAgo": "Днів тому",
+ "today": "Сьогодні",
+ "loading": "Завантаження..."
+ },
+ "login": "Логін"
}
From c3c1e2f39a597f25e6448aad860287e6f7103fc4 Mon Sep 17 00:00:00 2001
From: Arif Budiman
Date: Sun, 29 Mar 2026 09:19:20 +0200
Subject: [PATCH 06/64] Translated using Weblate (Indonesian)
Currently translated at 100.0% (103 of 103 strings)
Translation: Nezha/User frontend
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/id/
---
src/locales/id/translation.json | 132 +++++++++++++++++++++++++++++---
1 file changed, 121 insertions(+), 11 deletions(-)
diff --git a/src/locales/id/translation.json b/src/locales/id/translation.json
index fc4fa59..430cf9d 100644
--- a/src/locales/id/translation.json
+++ b/src/locales/id/translation.json
@@ -1,11 +1,11 @@
{
- "nezha": "Monitor Nezha",
- "overview": "Ringkasan",
+ "nezha": "Pemantauan Nezha",
+ "overview": "Ikhtisar",
"dashboard": "Dasbor",
"login": "Masuk",
- "online": "Online",
- "offline": "Offline",
- "whereTheTimeIs": "Dimana waktunya",
+ "online": "Daring",
+ "offline": "Luring",
+ "whereTheTimeIs": "Di mana waktunya",
"refreshing": "Menyegarkan",
"info": {
"websocketConnecting": "WebSocket menghubungkan",
@@ -14,14 +14,124 @@
"websocketConnected": "WebSocket terhubung"
},
"serverOverview": {
- "totalServers": "Jumlah Server",
- "onlineServers": "Online Server",
- "offlineServers": "Offline Server",
+ "totalServers": "Total Server",
+ "onlineServers": "Server Daring",
+ "offlineServers": "Server Luring",
"speed": "Kecepatan",
- "totalBandwidth": "Jumlah Bandwidth"
+ "totalBandwidth": "Total Bandwidth",
+ "network": "Jaringan"
},
"theme": {
"light": "Terang",
- "dark": "Gelap"
- }
+ "dark": "Gelap",
+ "system": "Sistem"
+ },
+ "map": {
+ "Distributions": "Server didistribusikan di",
+ "Regions": "Wilayah",
+ "Servers": "server"
+ },
+ "serverCard": {
+ "mem": "MEM",
+ "stg": "STG",
+ "days": "Hari",
+ "hours": "Jam",
+ "upload": "Unggah",
+ "download": "Unduh",
+ "system": "Sistem",
+ "uptime": "Waktu aktif",
+ "totalUpload": "Unggah",
+ "totalDownload": "Unduh"
+ },
+ "cycleTransfer": {
+ "used": "digunakan",
+ "total": "total",
+ "nextUpdate": "pembaruan berikutnya"
+ },
+ "serviceTracker": {
+ "noService": "Tidak ada data layanan",
+ "uptime": "Waktu aktif",
+ "delay": "Tunda",
+ "daysAgo": "hari yang lalu",
+ "today": "Hari ini",
+ "loading": "Memuat..."
+ },
+ "serverDetail": {
+ "status": "Status",
+ "online": "Daring",
+ "days": "Hari",
+ "hours": "Jam",
+ "offline": "Luring",
+ "unknown": "Tidak diketahui",
+ "uptime": "Waktu aktif",
+ "version": "Versi",
+ "arch": "Arsitektur",
+ "mem": "Memori",
+ "disk": "Disk",
+ "region": "Wilayah",
+ "system": "Sistem",
+ "upload": "Unggah",
+ "download": "Unduh",
+ "lastActive": "Waktu aktif terakhir",
+ "temperature": "Suhu",
+ "bootTime": "Waktu boot"
+ },
+ "serverDetailChart": {
+ "process": "Proses",
+ "disk": "Disk",
+ "mem": "Memori",
+ "swap": "Swap",
+ "upload": "Unggah",
+ "download": "Unduh"
+ },
+ "footer": {
+ "themeBy": "Tema oleh "
+ },
+ "language": {
+ "zh-CN": "简体中文",
+ "zh-TW": "繁體中文",
+ "en-US": "Inggris",
+ "de-DE": "Jerman",
+ "es-ES": "Spanyol",
+ "ru-RU": "Rusia",
+ "ta-IN": "Tamil"
+ },
+ "error": {
+ "pageNotFound": "Halaman tidak ditemukan",
+ "backToHome": "Kembali ke beranda"
+ },
+ "tabSwitch": {
+ "Detail": "Detail",
+ "Network": "Jaringan"
+ },
+ "monitor": {
+ "noData": "Tidak ada data pemantauan server, harap tambahkan pemantauan layanan terlebih dahulu",
+ "avgDelay": "Latensi",
+ "monitorCount": "Layanan",
+ "packetLoss": "Kehilangan Paket",
+ "clearSelections": "Bersihkan"
+ },
+ "pwa": {
+ "offlineReady": "Aplikasi siap bekerja luring",
+ "newContent": "Konten baru tersedia",
+ "reload": "Perbarui"
+ },
+ "billingInfo": {
+ "remaining": "Tersisa",
+ "error": "galat",
+ "indefinite": "Tak terbatas",
+ "expired": "Kedaluwarsa",
+ "days": "hari",
+ "price": "Harga",
+ "free": "Gratis",
+ "usage-baseed": "Berdasarkan penggunaan"
+ },
+ "TypeCommand": "Ketik perintah atau cari...",
+ "NoResults": "Tidak ada hasil ditemukan.",
+ "Servers": "Server",
+ "Shortcuts": "Jalan pintas",
+ "ToggleLightMode": "Alihkan Mode Terang",
+ "ToggleDarkMode": "Alihkan Mode Gelap",
+ "ToggleSystemMode": "Alihkan Mode Sistem",
+ "Home": "Beranda"
}
From a1b382c3eb1ae5670de796e292c77547c4fb257e Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Mon, 25 May 2026 01:42:43 +0800
Subject: [PATCH 07/64] fix: update dependencies in package.json to latest
versions
---
package.json | 80 +-
pnpm-lock.yaml | 2294 ++++++++++++++++++++++--------------------------
vite.config.ts | 2 +-
3 files changed, 1066 insertions(+), 1310 deletions(-)
diff --git a/package.json b/package.json
index add4a79..1a132bb 100644
--- a/package.json
+++ b/package.json
@@ -14,56 +14,56 @@
"preview": "vite preview"
},
"dependencies": {
- "@fontsource/inter": "5.1.1",
+ "@fontsource/inter": "5.2.8",
"@heroicons/react": "2.2.0",
- "@radix-ui/react-accordion": "1.2.3",
- "@radix-ui/react-checkbox": "1.1.4",
+ "@radix-ui/react-accordion": "1.2.12",
+ "@radix-ui/react-checkbox": "1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
- "@radix-ui/react-dropdown-menu": "2.1.6",
- "@radix-ui/react-label": "2.1.2",
- "@radix-ui/react-popover": "1.1.6",
- "@radix-ui/react-progress": "1.1.2",
- "@radix-ui/react-select": "2.1.6",
- "@radix-ui/react-separator": "1.1.2",
- "@radix-ui/react-slot": "1.1.2",
- "@radix-ui/react-switch": "1.1.3",
- "@radix-ui/react-tooltip": "1.1.8",
- "@tanstack/react-query": "5.66.7",
- "@tanstack/react-query-devtools": "5.66.7",
- "@tanstack/react-table": "8.21.2",
+ "@radix-ui/react-dropdown-menu": "2.1.16",
+ "@radix-ui/react-label": "2.1.8",
+ "@radix-ui/react-popover": "1.1.15",
+ "@radix-ui/react-progress": "1.1.8",
+ "@radix-ui/react-select": "2.2.6",
+ "@radix-ui/react-separator": "1.1.8",
+ "@radix-ui/react-slot": "1.2.4",
+ "@radix-ui/react-switch": "1.2.6",
+ "@radix-ui/react-tooltip": "1.2.8",
+ "@tanstack/react-query": "5.100.14",
+ "@tanstack/react-query-devtools": "5.100.14",
+ "@tanstack/react-table": "8.21.3",
"@types/d3-geo": "3.1.0",
- "@types/luxon": "3.4.2",
+ "@types/luxon": "3.7.1",
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"cmdk": "1.1.1",
- "country-flag-icons": "1.5.18",
+ "country-flag-icons": "1.6.17",
"d3-geo": "3.1.1",
- "dayjs": "1.11.13",
- "framer-motion": "12.23.26",
+ "dayjs": "1.11.20",
+ "framer-motion": "12.40.0",
"i18n-iso-countries": "7.14.0",
- "i18next": "24.2.2",
- "lucide-react": "0.460.0",
- "luxon": "3.5.0",
- "react": "19.0.0",
- "react-dom": "19.0.0",
- "react-i18next": "15.4.1",
- "react-router-dom": "^7.13.2",
- "recharts": "2.15.1",
- "sonner": "1.7.4",
- "tailwind-merge": "2.6.0",
+ "i18next": "26.2.0",
+ "lucide-react": "1.16.0",
+ "luxon": "3.7.2",
+ "react": "19.2.6",
+ "react-dom": "19.2.6",
+ "react-i18next": "17.0.8",
+ "react-router-dom": "^7.15.1",
+ "recharts": "3.8.1",
+ "sonner": "2.0.7",
+ "tailwind-merge": "3.6.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
- "@biomejs/biome": "2.3.10",
- "@tailwindcss/postcss": "^4.2.2",
- "@types/node": "22.13.4",
- "@types/react": "19.0.10",
- "@types/react-dom": "19.0.4",
- "@vitejs/plugin-react": "^6.0.1",
- "globals": "15.15.0",
- "postcss": "8.5.3",
- "tailwindcss": "^4.2.2",
- "typescript": "~5.6.3",
- "vite": "8.0.3"
+ "@biomejs/biome": "2.4.15",
+ "@tailwindcss/postcss": "^4.3.0",
+ "@types/node": "25.9.1",
+ "@types/react": "19.2.15",
+ "@types/react-dom": "19.2.3",
+ "@vitejs/plugin-react": "^6.0.2",
+ "globals": "17.6.0",
+ "postcss": "8.5.15",
+ "tailwindcss": "^4.3.0",
+ "typescript": "~6.0.3",
+ "vite": "8.0.14"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ac638db..37ad98e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,62 +9,62 @@ importers:
.:
dependencies:
'@fontsource/inter':
- specifier: 5.1.1
- version: 5.1.1
+ specifier: 5.2.8
+ version: 5.2.8
'@heroicons/react':
specifier: 2.2.0
- version: 2.2.0(react@19.0.0)
+ version: 2.2.0(react@19.2.6)
'@radix-ui/react-accordion':
- specifier: 1.2.3
- version: 1.2.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 1.2.12
+ version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-checkbox':
- specifier: 1.1.4
- version: 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 1.3.3
+ version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-dialog':
specifier: ^1.1.15
- version: 1.1.15(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-dropdown-menu':
- specifier: 2.1.6
- version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 2.1.16
+ version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-label':
- specifier: 2.1.2
- version: 2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 2.1.8
+ version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-popover':
- specifier: 1.1.6
- version: 1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 1.1.15
+ version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@radix-ui/react-progress':
- specifier: 1.1.2
- version: 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-select':
- specifier: 2.1.6
- version: 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-separator':
- specifier: 1.1.2
- version: 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot':
- specifier: 1.1.2
- version: 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-switch':
- specifier: 1.1.3
- version: 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-tooltip':
specifier: 1.1.8
- version: 1.1.8(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-select':
+ specifier: 2.2.6
+ version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-separator':
+ specifier: 1.1.8
+ version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot':
+ specifier: 1.2.4
+ version: 1.2.4(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-switch':
+ specifier: 1.2.6
+ version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-tooltip':
+ specifier: 1.2.8
+ version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/react-query':
- specifier: 5.66.7
- version: 5.66.7(react@19.0.0)
+ specifier: 5.100.14
+ version: 5.100.14(react@19.2.6)
'@tanstack/react-query-devtools':
- specifier: 5.66.7
- version: 5.66.7(@tanstack/react-query@5.66.7(react@19.0.0))(react@19.0.0)
+ specifier: 5.100.14
+ version: 5.100.14(@tanstack/react-query@5.100.14(react@19.2.6))(react@19.2.6)
'@tanstack/react-table':
- specifier: 8.21.2
- version: 8.21.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 8.21.3
+ version: 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@types/d3-geo':
specifier: 3.1.0
version: 3.1.0
'@types/luxon':
- specifier: 3.4.2
- version: 3.4.2
+ specifier: 3.7.1
+ version: 3.7.1
class-variance-authority:
specifier: 0.7.1
version: 0.7.1
@@ -73,89 +73,89 @@ importers:
version: 2.1.1
cmdk:
specifier: 1.1.1
- version: 1.1.1(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
country-flag-icons:
- specifier: 1.5.18
- version: 1.5.18
+ specifier: 1.6.17
+ version: 1.6.17
d3-geo:
specifier: 3.1.1
version: 3.1.1
dayjs:
- specifier: 1.11.13
- version: 1.11.13
+ specifier: 1.11.20
+ version: 1.11.20
framer-motion:
- specifier: 12.23.26
- version: 12.23.26(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 12.40.0
+ version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
i18n-iso-countries:
specifier: 7.14.0
version: 7.14.0
i18next:
- specifier: 24.2.2
- version: 24.2.2(typescript@5.6.3)
+ specifier: 26.2.0
+ version: 26.2.0(typescript@6.0.3)
lucide-react:
- specifier: 0.460.0
- version: 0.460.0(react@19.0.0)
+ specifier: 1.16.0
+ version: 1.16.0(react@19.2.6)
luxon:
- specifier: 3.5.0
- version: 3.5.0
+ specifier: 3.7.2
+ version: 3.7.2
react:
- specifier: 19.0.0
- version: 19.0.0
+ specifier: 19.2.6
+ version: 19.2.6
react-dom:
- specifier: 19.0.0
- version: 19.0.0(react@19.0.0)
+ specifier: 19.2.6
+ version: 19.2.6(react@19.2.6)
react-i18next:
- specifier: 15.4.1
- version: 15.4.1(i18next@24.2.2(typescript@5.6.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 17.0.8
+ version: 17.0.8(i18next@26.2.0(typescript@6.0.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3)
react-router-dom:
- specifier: ^7.13.2
- version: 7.13.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: ^7.15.1
+ version: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
recharts:
- specifier: 2.15.1
- version: 2.15.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 3.8.1
+ version: 3.8.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react-is@18.3.1)(react@19.2.6)(redux@5.0.1)
sonner:
- specifier: 1.7.4
- version: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ specifier: 2.0.7
+ version: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
tailwind-merge:
- specifier: 2.6.0
- version: 2.6.0
+ specifier: 3.6.0
+ version: 3.6.0
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@4.2.2)
+ version: 1.0.7(tailwindcss@4.3.0)
devDependencies:
'@biomejs/biome':
- specifier: 2.3.10
- version: 2.3.10
+ specifier: 2.4.15
+ version: 2.4.15
'@tailwindcss/postcss':
- specifier: ^4.2.2
- version: 4.2.2
+ specifier: ^4.3.0
+ version: 4.3.0
'@types/node':
- specifier: 22.13.4
- version: 22.13.4
+ specifier: 25.9.1
+ version: 25.9.1
'@types/react':
- specifier: 19.0.10
- version: 19.0.10
+ specifier: 19.2.15
+ version: 19.2.15
'@types/react-dom':
- specifier: 19.0.4
- version: 19.0.4(@types/react@19.0.10)
+ specifier: 19.2.3
+ version: 19.2.3(@types/react@19.2.15)
'@vitejs/plugin-react':
- specifier: ^6.0.1
- version: 6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.13.4)(jiti@2.6.1))
+ specifier: ^6.0.2
+ version: 6.0.2(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0))
globals:
- specifier: 15.15.0
- version: 15.15.0
+ specifier: 17.6.0
+ version: 17.6.0
postcss:
- specifier: 8.5.3
- version: 8.5.3
+ specifier: 8.5.15
+ version: 8.5.15
tailwindcss:
- specifier: ^4.2.2
- version: 4.2.2
+ specifier: ^4.3.0
+ version: 4.3.0
typescript:
- specifier: ~5.6.3
- version: 5.6.3
+ specifier: ~6.0.3
+ version: 6.0.3
vite:
- specifier: 8.0.3
- version: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.13.4)(jiti@2.6.1)
+ specifier: 8.0.14
+ version: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)
packages:
@@ -167,71 +167,71 @@ packages:
resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==}
engines: {node: '>=6.9.0'}
- '@biomejs/biome@2.3.10':
- resolution: {integrity: sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ==}
+ '@biomejs/biome@2.4.15':
+ resolution: {integrity: sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@2.3.10':
- resolution: {integrity: sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w==}
+ '@biomejs/cli-darwin-arm64@2.4.15':
+ resolution: {integrity: sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@2.3.10':
- resolution: {integrity: sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg==}
+ '@biomejs/cli-darwin-x64@2.4.15':
+ resolution: {integrity: sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@2.3.10':
- resolution: {integrity: sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A==}
+ '@biomejs/cli-linux-arm64-musl@2.4.15':
+ resolution: {integrity: sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@biomejs/cli-linux-arm64@2.3.10':
- resolution: {integrity: sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA==}
+ '@biomejs/cli-linux-arm64@2.4.15':
+ resolution: {integrity: sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@biomejs/cli-linux-x64-musl@2.3.10':
- resolution: {integrity: sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g==}
+ '@biomejs/cli-linux-x64-musl@2.4.15':
+ resolution: {integrity: sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
libc: [musl]
- '@biomejs/cli-linux-x64@2.3.10':
- resolution: {integrity: sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw==}
+ '@biomejs/cli-linux-x64@2.4.15':
+ resolution: {integrity: sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@biomejs/cli-win32-arm64@2.3.10':
- resolution: {integrity: sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ==}
+ '@biomejs/cli-win32-arm64@2.4.15':
+ resolution: {integrity: sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@2.3.10':
- resolution: {integrity: sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ==}
+ '@biomejs/cli-win32-x64@2.4.15':
+ resolution: {integrity: sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
- '@emnapi/core@1.9.1':
- resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==}
+ '@emnapi/core@1.10.0':
+ resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==}
- '@emnapi/runtime@1.9.1':
- resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==}
+ '@emnapi/runtime@1.10.0':
+ resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==}
- '@emnapi/wasi-threads@1.2.0':
- resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==}
+ '@emnapi/wasi-threads@1.2.1':
+ resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
'@floating-ui/core@1.7.5':
resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==}
@@ -248,8 +248,8 @@ packages:
'@floating-ui/utils@0.2.11':
resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==}
- '@fontsource/inter@5.1.1':
- resolution: {integrity: sha512-weN3E+rq0Xb3Z93VHJ+Rc7WOQX9ETJPTAJ+gDcaMHtjft67L58sfS65rAjC5tZUXQ2FdZ/V1/sSzCwZ6v05kJw==}
+ '@fontsource/inter@5.2.8':
+ resolution: {integrity: sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==}
'@heroicons/react@2.2.0':
resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==}
@@ -272,26 +272,23 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
- '@napi-rs/wasm-runtime@1.1.2':
- resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==}
+ '@napi-rs/wasm-runtime@1.1.4':
+ resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
peerDependencies:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
- '@oxc-project/types@0.122.0':
- resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==}
+ '@oxc-project/types@0.132.0':
+ resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==}
- '@radix-ui/number@1.1.0':
- resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==}
-
- '@radix-ui/primitive@1.1.1':
- resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
+ '@radix-ui/number@1.1.1':
+ resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
'@radix-ui/primitive@1.1.3':
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
- '@radix-ui/react-accordion@1.2.3':
- resolution: {integrity: sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A==}
+ '@radix-ui/react-accordion@1.2.12':
+ resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -303,8 +300,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-arrow@1.1.2':
- resolution: {integrity: sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==}
+ '@radix-ui/react-arrow@1.1.7':
+ resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -316,8 +313,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-checkbox@1.1.4':
- resolution: {integrity: sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==}
+ '@radix-ui/react-checkbox@1.3.3':
+ resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -329,8 +326,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-collapsible@1.1.3':
- resolution: {integrity: sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw==}
+ '@radix-ui/react-collapsible@1.1.12':
+ resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -342,8 +339,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-collection@1.1.2':
- resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==}
+ '@radix-ui/react-collection@1.1.7':
+ resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -355,15 +352,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-compose-refs@1.1.1':
- resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-compose-refs@1.1.2':
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
peerDependencies:
@@ -373,8 +361,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-context@1.1.1':
- resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==}
+ '@radix-ui/react-context@1.1.2':
+ resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -382,8 +370,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-context@1.1.2':
- resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==}
+ '@radix-ui/react-context@1.1.3':
+ resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -404,8 +392,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-direction@1.1.0':
- resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==}
+ '@radix-ui/react-direction@1.1.1':
+ resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -426,8 +414,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-dismissable-layer@1.1.5':
- resolution: {integrity: sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==}
+ '@radix-ui/react-dropdown-menu@2.1.16':
+ resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -439,28 +427,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-dropdown-menu@2.1.6':
- resolution: {integrity: sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-focus-guards@1.1.1':
- resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-focus-guards@1.1.3':
resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==}
peerDependencies:
@@ -470,19 +436,6 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-focus-scope@1.1.2':
- resolution: {integrity: sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
'@radix-ui/react-focus-scope@1.1.7':
resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==}
peerDependencies:
@@ -496,15 +449,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-id@1.1.0':
- resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-id@1.1.1':
resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
peerDependencies:
@@ -514,8 +458,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-label@2.1.2':
- resolution: {integrity: sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw==}
+ '@radix-ui/react-label@2.1.8':
+ resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -527,8 +471,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-menu@2.1.6':
- resolution: {integrity: sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg==}
+ '@radix-ui/react-menu@2.1.16':
+ resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -540,8 +484,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-popover@1.1.6':
- resolution: {integrity: sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg==}
+ '@radix-ui/react-popover@1.1.15':
+ resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -553,21 +497,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-popper@1.2.2':
- resolution: {integrity: sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-portal@1.1.4':
- resolution: {integrity: sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==}
+ '@radix-ui/react-popper@1.2.8':
+ resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -592,19 +523,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-presence@1.1.2':
- resolution: {integrity: sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
'@radix-ui/react-presence@1.1.5':
resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==}
peerDependencies:
@@ -618,19 +536,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-primitive@2.0.2':
- resolution: {integrity: sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
'@radix-ui/react-primitive@2.1.3':
resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==}
peerDependencies:
@@ -657,8 +562,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-progress@1.1.2':
- resolution: {integrity: sha512-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA==}
+ '@radix-ui/react-progress@1.1.8':
+ resolution: {integrity: sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -670,8 +575,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-roving-focus@1.1.2':
- resolution: {integrity: sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw==}
+ '@radix-ui/react-roving-focus@1.1.11':
+ resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -683,8 +588,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-select@2.1.6':
- resolution: {integrity: sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==}
+ '@radix-ui/react-select@2.2.6':
+ resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -696,8 +601,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-separator@1.1.2':
- resolution: {integrity: sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ==}
+ '@radix-ui/react-separator@1.1.8':
+ resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -709,15 +614,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-slot@1.1.2':
- resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-slot@1.2.3':
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
peerDependencies:
@@ -736,8 +632,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-switch@1.1.3':
- resolution: {integrity: sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ==}
+ '@radix-ui/react-switch@1.2.6':
+ resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -749,8 +645,8 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-tooltip@1.1.8':
- resolution: {integrity: sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==}
+ '@radix-ui/react-tooltip@1.2.8':
+ resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -762,15 +658,6 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/react-use-callback-ref@1.1.0':
- resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-use-callback-ref@1.1.1':
resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==}
peerDependencies:
@@ -780,15 +667,6 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-controllable-state@1.1.0':
- resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-use-controllable-state@1.2.2':
resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==}
peerDependencies:
@@ -807,15 +685,6 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-escape-keydown@1.1.0':
- resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-use-escape-keydown@1.1.1':
resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==}
peerDependencies:
@@ -825,15 +694,6 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-layout-effect@1.1.0':
- resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
'@radix-ui/react-use-layout-effect@1.1.1':
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
peerDependencies:
@@ -843,8 +703,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-previous@1.1.0':
- resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==}
+ '@radix-ui/react-use-previous@1.1.1':
+ resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -852,8 +712,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-rect@1.1.0':
- resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==}
+ '@radix-ui/react-use-rect@1.1.1':
+ resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -861,8 +721,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-use-size@1.1.0':
- resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==}
+ '@radix-ui/react-use-size@1.1.1':
+ resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
@@ -870,8 +730,8 @@ packages:
'@types/react':
optional: true
- '@radix-ui/react-visually-hidden@1.1.2':
- resolution: {integrity: sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==}
+ '@radix-ui/react-visually-hidden@1.2.3':
+ resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
@@ -883,173 +743,187 @@ packages:
'@types/react-dom':
optional: true
- '@radix-ui/rect@1.1.0':
- resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
+ '@radix-ui/rect@1.1.1':
+ resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
- '@rolldown/binding-android-arm64@1.0.0-rc.12':
- resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==}
+ '@reduxjs/toolkit@2.12.0':
+ resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==}
+ peerDependencies:
+ react: ^16.9.0 || ^17.0.0 || ^18 || ^19
+ react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-redux:
+ optional: true
+
+ '@rolldown/binding-android-arm64@1.0.2':
+ resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
- '@rolldown/binding-darwin-arm64@1.0.0-rc.12':
- resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==}
+ '@rolldown/binding-darwin-arm64@1.0.2':
+ resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
- '@rolldown/binding-darwin-x64@1.0.0-rc.12':
- resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==}
+ '@rolldown/binding-darwin-x64@1.0.2':
+ resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
- '@rolldown/binding-freebsd-x64@1.0.0-rc.12':
- resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==}
+ '@rolldown/binding-freebsd-x64@1.0.2':
+ resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12':
- resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==}
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.2':
+ resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12':
- resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==}
+ '@rolldown/binding-linux-arm64-gnu@1.0.2':
+ resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12':
- resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==}
+ '@rolldown/binding-linux-arm64-musl@1.0.2':
+ resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12':
- resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==}
+ '@rolldown/binding-linux-ppc64-gnu@1.0.2':
+ resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12':
- resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==}
+ '@rolldown/binding-linux-s390x-gnu@1.0.2':
+ resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12':
- resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==}
+ '@rolldown/binding-linux-x64-gnu@1.0.2':
+ resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.12':
- resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==}
+ '@rolldown/binding-linux-x64-musl@1.0.2':
+ resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.12':
- resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==}
+ '@rolldown/binding-openharmony-arm64@1.0.2':
+ resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.12':
- resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==}
- engines: {node: '>=14.0.0'}
+ '@rolldown/binding-wasm32-wasi@1.0.2':
+ resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
cpu: [wasm32]
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12':
- resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==}
+ '@rolldown/binding-win32-arm64-msvc@1.0.2':
+ resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12':
- resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==}
+ '@rolldown/binding-win32-x64-msvc@1.0.2':
+ resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
- '@rolldown/pluginutils@1.0.0-rc.12':
- resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==}
+ '@rolldown/pluginutils@1.0.1':
+ resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
- '@rolldown/pluginutils@1.0.0-rc.7':
- resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
+ '@standard-schema/spec@1.1.0':
+ resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
- '@tailwindcss/node@4.2.2':
- resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==}
+ '@standard-schema/utils@0.3.0':
+ resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
- '@tailwindcss/oxide-android-arm64@4.2.2':
- resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==}
+ '@tailwindcss/node@4.3.0':
+ resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==}
+
+ '@tailwindcss/oxide-android-arm64@4.3.0':
+ resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [android]
- '@tailwindcss/oxide-darwin-arm64@4.2.2':
- resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==}
+ '@tailwindcss/oxide-darwin-arm64@4.3.0':
+ resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [darwin]
- '@tailwindcss/oxide-darwin-x64@4.2.2':
- resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==}
+ '@tailwindcss/oxide-darwin-x64@4.3.0':
+ resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==}
engines: {node: '>= 20'}
cpu: [x64]
os: [darwin]
- '@tailwindcss/oxide-freebsd-x64@4.2.2':
- resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==}
+ '@tailwindcss/oxide-freebsd-x64@4.3.0':
+ resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==}
engines: {node: '>= 20'}
cpu: [x64]
os: [freebsd]
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2':
- resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==}
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0':
+ resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==}
engines: {node: '>= 20'}
cpu: [arm]
os: [linux]
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.2':
- resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==}
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.0':
+ resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@tailwindcss/oxide-linux-arm64-musl@4.2.2':
- resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==}
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.0':
+ resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@tailwindcss/oxide-linux-x64-gnu@4.2.2':
- resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==}
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.0':
+ resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@tailwindcss/oxide-linux-x64-musl@4.2.2':
- resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==}
+ '@tailwindcss/oxide-linux-x64-musl@4.3.0':
+ resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
libc: [musl]
- '@tailwindcss/oxide-wasm32-wasi@4.2.2':
- resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==}
+ '@tailwindcss/oxide-wasm32-wasi@4.3.0':
+ resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
bundledDependencies:
@@ -1060,55 +934,55 @@ packages:
- '@emnapi/wasi-threads'
- tslib
- '@tailwindcss/oxide-win32-arm64-msvc@4.2.2':
- resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==}
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.0':
+ resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [win32]
- '@tailwindcss/oxide-win32-x64-msvc@4.2.2':
- resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==}
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.0':
+ resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==}
engines: {node: '>= 20'}
cpu: [x64]
os: [win32]
- '@tailwindcss/oxide@4.2.2':
- resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==}
+ '@tailwindcss/oxide@4.3.0':
+ resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==}
engines: {node: '>= 20'}
- '@tailwindcss/postcss@4.2.2':
- resolution: {integrity: sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==}
+ '@tailwindcss/postcss@4.3.0':
+ resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==}
- '@tanstack/query-core@5.66.4':
- resolution: {integrity: sha512-skM/gzNX4shPkqmdTCSoHtJAPMTtmIJNS0hE+xwTTUVYwezArCT34NMermABmBVUg5Ls5aiUXEDXfqwR1oVkcA==}
+ '@tanstack/query-core@5.100.14':
+ resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==}
- '@tanstack/query-devtools@5.65.0':
- resolution: {integrity: sha512-g5y7zc07U9D3esMdqUfTEVu9kMHoIaVBsD0+M3LPdAdD710RpTcLiNvJY1JkYXqkq9+NV+CQoemVNpQPBXVsJg==}
+ '@tanstack/query-devtools@5.100.14':
+ resolution: {integrity: sha512-g96SmSSQecYTYcyuAMRXr895GplJv01UGt7qttQWPOUyZ5EGz5tbRc589bMc2m5BsPFD6O0PCEAHdbDYNP6UBw==}
- '@tanstack/react-query-devtools@5.66.7':
- resolution: {integrity: sha512-40z4PPkz06tYIF0vwLZZIZfZxKUH4OAaBOR14blCFyYm6hlU6qc+M82mkZ+D00HcEMhV7P4XeJiEuDhFq0q9Qw==}
+ '@tanstack/react-query-devtools@5.100.14':
+ resolution: {integrity: sha512-JkP5VDgKOw3t/QSA1OABRHEqx8BuNs5MfvZRooNqdvN57SzTuGq3fKR1a2IH5rqa5HDLUm+FOXUEnB9ueHiLzg==}
peerDependencies:
- '@tanstack/react-query': ^5.66.7
+ '@tanstack/react-query': ^5.100.14
react: ^18 || ^19
- '@tanstack/react-query@5.66.7':
- resolution: {integrity: sha512-qd3q/tUpF2K1xItfPZddk1k/8pSXnovg41XyCqJgPoyYEirMBtB0sVEVVQ/CsAOngzgWtBPXimVf4q4kM9uO6A==}
+ '@tanstack/react-query@5.100.14':
+ resolution: {integrity: sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==}
peerDependencies:
react: ^18 || ^19
- '@tanstack/react-table@8.21.2':
- resolution: {integrity: sha512-11tNlEDTdIhMJba2RBH+ecJ9l1zgS2kjmexDPAraulc8jeNA4xocSNeyzextT0XJyASil4XsCYlJmf5jEWAtYg==}
+ '@tanstack/react-table@8.21.3':
+ resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==}
engines: {node: '>=12'}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
- '@tanstack/table-core@8.21.2':
- resolution: {integrity: sha512-uvXk/U4cBiFMxt+p9/G7yUWI/UbHYbyghLCjlpWZ3mLeIZiUBSKcUnw9UnKkdRz7Z/N4UBuFLWQdJCjUe7HjvA==}
+ '@tanstack/table-core@8.21.3':
+ resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==}
engines: {node: '>=12'}
- '@tybys/wasm-util@0.10.1':
- resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+ '@tybys/wasm-util@0.10.2':
+ resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/d3-array@3.2.2':
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
@@ -1143,22 +1017,25 @@ packages:
'@types/geojson@7946.0.16':
resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==}
- '@types/luxon@3.4.2':
- resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==}
+ '@types/luxon@3.7.1':
+ resolution: {integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==}
- '@types/node@22.13.4':
- resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==}
+ '@types/node@25.9.1':
+ resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==}
- '@types/react-dom@19.0.4':
- resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==}
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
- '@types/react': ^19.0.0
+ '@types/react': ^19.2.0
- '@types/react@19.0.10':
- resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==}
+ '@types/react@19.2.15':
+ resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==}
- '@vitejs/plugin-react@6.0.1':
- resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
+ '@types/use-sync-external-store@0.0.6':
+ resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
+
+ '@vitejs/plugin-react@6.0.2':
+ resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
'@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
@@ -1191,8 +1068,8 @@ packages:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
- country-flag-icons@1.5.18:
- resolution: {integrity: sha512-z+Uzesi8u8IdkViqqbzzbkf3+a7WJpcET5B7sPwTg7GXqPYpVEgNlZ/FC3l8KO4mEf+mNkmzKLppKTN4PlCJEQ==}
+ country-flag-icons@1.6.17:
+ resolution: {integrity: sha512-Nmik0289ZVZSI3c7mJR/amg6DyY7Z59b0sTFSKayeX72mHfPzCPJygwJs2pYgQULzuAyWeCUgwAJ+Dq8OR+JFw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
@@ -1245,8 +1122,8 @@ packages:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
- dayjs@1.11.13:
- resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+ dayjs@1.11.20:
+ resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==}
decimal.js-light@2.5.1:
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
@@ -1261,19 +1138,15 @@ packages:
diacritics@1.3.0:
resolution: {integrity: sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA==}
- dom-helpers@5.2.1:
- resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
-
- enhanced-resolve@5.20.1:
- resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==}
+ enhanced-resolve@5.22.0:
+ resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==}
engines: {node: '>=10.13.0'}
- eventemitter3@4.0.7:
- resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ es-toolkit@1.46.1:
+ resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==}
- fast-equals@5.4.0:
- resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==}
- engines: {node: '>=6.0.0'}
+ eventemitter3@5.0.4:
+ resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
@@ -1284,8 +1157,8 @@ packages:
picomatch:
optional: true
- framer-motion@12.23.26:
- resolution: {integrity: sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==}
+ framer-motion@12.40.0:
+ resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0 || ^19.0.0
@@ -1307,8 +1180,8 @@ packages:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
- globals@15.15.0:
- resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
+ globals@17.6.0:
+ resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==}
engines: {node: '>=18'}
graceful-fs@4.2.11:
@@ -1321,25 +1194,28 @@ packages:
resolution: {integrity: sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg==}
engines: {node: '>= 12'}
- i18next@24.2.2:
- resolution: {integrity: sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ==}
+ i18next@26.2.0:
+ resolution: {integrity: sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA==}
peerDependencies:
- typescript: ^5
+ typescript: ^5 || ^6
peerDependenciesMeta:
typescript:
optional: true
+ immer@10.2.0:
+ resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
+
+ immer@11.1.8:
+ resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==}
+
internmap@2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
- jiti@2.6.1:
- resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ jiti@2.7.0:
+ resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
hasBin: true
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
lightningcss-android-arm64@1.32.0:
resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
engines: {node: '>= 12.0.0'}
@@ -1414,40 +1290,29 @@ packages:
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
engines: {node: '>= 12.0.0'}
- lodash@4.18.1:
- resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
-
- loose-envify@1.4.0:
- resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
- hasBin: true
-
- lucide-react@0.460.0:
- resolution: {integrity: sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg==}
+ lucide-react@1.16.0:
+ resolution: {integrity: sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==}
peerDependencies:
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
- luxon@3.5.0:
- resolution: {integrity: sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==}
+ luxon@3.7.2:
+ resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
engines: {node: '>=12'}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- motion-dom@12.38.0:
- resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==}
+ motion-dom@12.40.0:
+ resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==}
- motion-utils@12.36.0:
- resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==}
+ motion-utils@12.39.0:
+ resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==}
- nanoid@3.3.11:
- resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ nanoid@3.3.12:
+ resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
-
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -1455,41 +1320,46 @@ packages:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
- postcss@8.5.3:
- resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+ postcss@8.5.15:
+ resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.8:
- resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
- engines: {node: ^10 || ^12 || >=14}
-
- prop-types@15.8.1:
- resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
-
- react-dom@19.0.0:
- resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==}
+ react-dom@19.2.6:
+ resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==}
peerDependencies:
- react: ^19.0.0
+ react: ^19.2.6
- react-i18next@15.4.1:
- resolution: {integrity: sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw==}
+ react-i18next@17.0.8:
+ resolution: {integrity: sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw==}
peerDependencies:
- i18next: '>= 23.2.3'
+ i18next: '>= 26.2.0'
react: '>= 16.8.0'
react-dom: '*'
react-native: '*'
+ typescript: ^5 || ^6
peerDependenciesMeta:
react-dom:
optional: true
react-native:
optional: true
-
- react-is@16.13.1:
- resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ typescript:
+ optional: true
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
+ react-redux@9.3.0:
+ resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==}
+ peerDependencies:
+ '@types/react': ^18.2.25 || ^19
+ react: ^18.0 || ^19
+ redux: ^5.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ redux:
+ optional: true
+
react-remove-scroll-bar@2.3.8:
resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
engines: {node: '>=10'}
@@ -1510,15 +1380,15 @@ packages:
'@types/react':
optional: true
- react-router-dom@7.13.2:
- resolution: {integrity: sha512-aR7SUORwTqAW0JDeiWF07e9SBE9qGpByR9I8kJT5h/FrBKxPMS6TiC7rmVO+gC0q52Bx7JnjWe8Z1sR9faN4YA==}
+ react-router-dom@7.15.1:
+ resolution: {integrity: sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==}
engines: {node: '>=20.0.0'}
peerDependencies:
react: '>=18'
react-dom: '>=18'
- react-router@7.13.2:
- resolution: {integrity: sha512-tX1Aee+ArlKQP+NIUd7SE6Li+CiGKwQtbS+FfRxPX6Pe4vHOo6nr9d++u5cwg+Z8K/x8tP+7qLmujDtfrAoUJA==}
+ react-router@7.15.1:
+ resolution: {integrity: sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==}
engines: {node: '>=20.0.0'}
peerDependencies:
react: '>=18'
@@ -1527,12 +1397,6 @@ packages:
react-dom:
optional: true
- react-smooth@4.0.4:
- resolution: {integrity: sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
react-style-singleton@2.2.3:
resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
engines: {node: '>=10'}
@@ -1543,39 +1407,42 @@ packages:
'@types/react':
optional: true
- react-transition-group@4.4.5:
- resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
- peerDependencies:
- react: '>=16.6.0'
- react-dom: '>=16.6.0'
-
- react@19.0.0:
- resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==}
+ react@19.2.6:
+ resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==}
engines: {node: '>=0.10.0'}
- recharts-scale@0.4.5:
- resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==}
-
- recharts@2.15.1:
- resolution: {integrity: sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q==}
- engines: {node: '>=14'}
+ recharts@3.8.1:
+ resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==}
+ engines: {node: '>=18'}
peerDependencies:
- react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- rolldown@1.0.0-rc.12:
- resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==}
+ redux-thunk@3.1.0:
+ resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
+ peerDependencies:
+ redux: ^5.0.0
+
+ redux@5.0.1:
+ resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
+
+ reselect@5.1.1:
+ resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
+
+ rolldown@1.0.2:
+ resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
- scheduler@0.25.0:
- resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==}
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
set-cookie-parser@2.7.2:
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
- sonner@1.7.4:
- resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==}
+ sonner@2.0.7:
+ resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
peerDependencies:
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
@@ -1584,38 +1451,38 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
- tailwind-merge@2.6.0:
- resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==}
+ tailwind-merge@3.6.0:
+ resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==}
tailwindcss-animate@1.0.7:
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
- tailwindcss@4.2.2:
- resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==}
+ tailwindcss@4.3.0:
+ resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==}
- tapable@2.3.2:
- resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==}
+ tapable@2.3.3:
+ resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
engines: {node: '>=6'}
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
- tinyglobby@0.2.15:
- resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
+ tinyglobby@0.2.16:
+ resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==}
engines: {node: '>=12.0.0'}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
- typescript@5.6.3:
- resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
+ typescript@6.0.3:
+ resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
engines: {node: '>=14.17'}
hasBin: true
- undici-types@6.20.0:
- resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
+ undici-types@7.24.6:
+ resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
use-callback-ref@1.3.3:
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
@@ -1637,17 +1504,22 @@ packages:
'@types/react':
optional: true
- victory-vendor@36.9.2:
- resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
+ use-sync-external-store@1.6.0:
+ resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- vite@8.0.3:
- resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==}
+ victory-vendor@37.3.6:
+ resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
+
+ vite@8.0.14:
+ resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
'@types/node': ^20.19.0 || >=22.12.0
- '@vitejs/devtools': ^0.1.0
- esbuild: ^0.27.0
+ '@vitejs/devtools': ^0.1.18
+ esbuild: ^0.27.0 || ^0.28.0
jiti: '>=1.21.0'
less: ^4.0.0
sass: ^1.70.0
@@ -1693,53 +1565,53 @@ snapshots:
'@babel/runtime@7.29.2': {}
- '@biomejs/biome@2.3.10':
+ '@biomejs/biome@2.4.15':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 2.3.10
- '@biomejs/cli-darwin-x64': 2.3.10
- '@biomejs/cli-linux-arm64': 2.3.10
- '@biomejs/cli-linux-arm64-musl': 2.3.10
- '@biomejs/cli-linux-x64': 2.3.10
- '@biomejs/cli-linux-x64-musl': 2.3.10
- '@biomejs/cli-win32-arm64': 2.3.10
- '@biomejs/cli-win32-x64': 2.3.10
+ '@biomejs/cli-darwin-arm64': 2.4.15
+ '@biomejs/cli-darwin-x64': 2.4.15
+ '@biomejs/cli-linux-arm64': 2.4.15
+ '@biomejs/cli-linux-arm64-musl': 2.4.15
+ '@biomejs/cli-linux-x64': 2.4.15
+ '@biomejs/cli-linux-x64-musl': 2.4.15
+ '@biomejs/cli-win32-arm64': 2.4.15
+ '@biomejs/cli-win32-x64': 2.4.15
- '@biomejs/cli-darwin-arm64@2.3.10':
+ '@biomejs/cli-darwin-arm64@2.4.15':
optional: true
- '@biomejs/cli-darwin-x64@2.3.10':
+ '@biomejs/cli-darwin-x64@2.4.15':
optional: true
- '@biomejs/cli-linux-arm64-musl@2.3.10':
+ '@biomejs/cli-linux-arm64-musl@2.4.15':
optional: true
- '@biomejs/cli-linux-arm64@2.3.10':
+ '@biomejs/cli-linux-arm64@2.4.15':
optional: true
- '@biomejs/cli-linux-x64-musl@2.3.10':
+ '@biomejs/cli-linux-x64-musl@2.4.15':
optional: true
- '@biomejs/cli-linux-x64@2.3.10':
+ '@biomejs/cli-linux-x64@2.4.15':
optional: true
- '@biomejs/cli-win32-arm64@2.3.10':
+ '@biomejs/cli-win32-arm64@2.4.15':
optional: true
- '@biomejs/cli-win32-x64@2.3.10':
+ '@biomejs/cli-win32-x64@2.4.15':
optional: true
- '@emnapi/core@1.9.1':
+ '@emnapi/core@1.10.0':
dependencies:
- '@emnapi/wasi-threads': 1.2.0
+ '@emnapi/wasi-threads': 1.2.1
tslib: 2.8.1
optional: true
- '@emnapi/runtime@1.9.1':
+ '@emnapi/runtime@1.10.0':
dependencies:
tslib: 2.8.1
optional: true
- '@emnapi/wasi-threads@1.2.0':
+ '@emnapi/wasi-threads@1.2.1':
dependencies:
tslib: 2.8.1
optional: true
@@ -1753,19 +1625,19 @@ snapshots:
'@floating-ui/core': 1.7.5
'@floating-ui/utils': 0.2.11
- '@floating-ui/react-dom@2.1.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@floating-ui/dom': 1.7.6
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
'@floating-ui/utils@0.2.11': {}
- '@fontsource/inter@5.1.1': {}
+ '@fontsource/inter@5.2.8': {}
- '@heroicons/react@2.2.0(react@19.0.0)':
+ '@heroicons/react@2.2.0(react@19.2.6)':
dependencies:
- react: 19.0.0
+ react: 19.2.6
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -1786,734 +1658,640 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
- '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)':
+ '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
dependencies:
- '@emnapi/core': 1.9.1
- '@emnapi/runtime': 1.9.1
- '@tybys/wasm-util': 0.10.1
+ '@emnapi/core': 1.10.0
+ '@emnapi/runtime': 1.10.0
+ '@tybys/wasm-util': 0.10.2
optional: true
- '@oxc-project/types@0.122.0': {}
+ '@oxc-project/types@0.132.0': {}
- '@radix-ui/number@1.1.0': {}
-
- '@radix-ui/primitive@1.1.1': {}
+ '@radix-ui/number@1.1.1': {}
'@radix-ui/primitive@1.1.3': {}
- '@radix-ui/react-accordion@1.2.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collapsible': 1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-collapsible@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-compose-refs@1.1.2(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-context@1.1.1(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-context@1.1.2(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@radix-ui/primitive': 1.1.3
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.2.3(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.0.10)(react@19.0.0)
- aria-hidden: 1.2.6
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-remove-scroll: 2.7.2(@types/react@19.0.10)(react@19.0.0)
+ '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-direction@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- react: 19.0.0
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@radix-ui/primitive': 1.1.3
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-dropdown-menu@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-menu': 2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- react: 19.0.0
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-focus-guards@1.1.3(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-context@1.1.2(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- react: 19.0.0
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-context@1.1.3(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
- '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-id@1.1.0(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-id@1.1.1(@types/react@19.0.10)(react@19.0.0)':
- dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- optionalDependencies:
- '@types/react': 19.0.10
-
- '@radix-ui/react-label@2.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-menu@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-roving-focus': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
aria-hidden: 1.2.6
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-remove-scroll: 2.7.2(@types/react@19.0.10)(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-popover@1.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-direction@1.1.1(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
+ react: 19.2.6
+ optionalDependencies:
+ '@types/react': 19.2.15
+
+ '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
+
+ '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
+
+ '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.15)(react@19.2.6)':
+ dependencies:
+ react: 19.2.6
+ optionalDependencies:
+ '@types/react': 19.2.15
+
+ '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
+
+ '@radix-ui/react-id@1.1.1(@types/react@19.2.15)(react@19.2.6)':
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ optionalDependencies:
+ '@types/react': 19.2.15
+
+ '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
+
+ '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
aria-hidden: 1.2.6
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-remove-scroll: 2.7.2(@types/react@19.0.10)(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-popper@1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@floating-ui/react-dom': 2.1.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-rect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/rect': 1.1.0
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-portal@1.1.9(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-presence@1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-slot': 1.2.3(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-slot': 1.2.4(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-progress@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-roving-focus@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
-
- '@radix-ui/react-select@2.1.6(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
- dependencies:
- '@radix-ui/number': 1.1.0
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-direction': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
aria-hidden: 1.2.6
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-remove-scroll: 2.7.2(@types/react@19.0.10)(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-separator@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/rect': 1.1.1
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-slot@1.1.2(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-slot@1.2.3(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-slot@1.2.4(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-switch@1.1.3(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/react-slot': 1.2.4(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-tooltip@1.1.8(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-progress@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/primitive': 1.1.1
- '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-context': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-slot': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/react-context': 1.1.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- react: 19.0.0
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- react: 19.0.0
+ '@radix-ui/number': 1.1.1
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ aria-hidden: 1.2.6
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-slot@1.2.3(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-slot@1.2.4(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
- '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- react: 19.0.0
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- react: 19.0.0
+ '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-previous@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- react: 19.0.0
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-rect@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/rect': 1.1.0
- react: 19.0.0
+ '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-use-size@1.1.0(@types/react@19.0.10)(react@19.0.0)':
+ '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.10)(react@19.0.0)
- react: 19.0.0
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.15)(react@19.2.6)':
dependencies:
- '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react: 19.2.6
optionalDependencies:
- '@types/react': 19.0.10
- '@types/react-dom': 19.0.4(@types/react@19.0.10)
+ '@types/react': 19.2.15
- '@radix-ui/rect@1.1.0': {}
+ '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.15)(react@19.2.6)':
+ dependencies:
+ '@radix-ui/rect': 1.1.1
+ react: 19.2.6
+ optionalDependencies:
+ '@types/react': 19.2.15
- '@rolldown/binding-android-arm64@1.0.0-rc.12':
+ '@radix-ui/react-use-size@1.1.1(@types/react@19.2.15)(react@19.2.6)':
+ dependencies:
+ '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ react: 19.2.6
+ optionalDependencies:
+ '@types/react': 19.2.15
+
+ '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
+ dependencies:
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ '@types/react-dom': 19.2.3(@types/react@19.2.15)
+
+ '@radix-ui/rect@1.1.1': {}
+
+ '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)':
+ dependencies:
+ '@standard-schema/spec': 1.1.0
+ '@standard-schema/utils': 0.3.0
+ immer: 11.1.8
+ redux: 5.0.1
+ redux-thunk: 3.1.0(redux@5.0.1)
+ reselect: 5.1.1
+ optionalDependencies:
+ react: 19.2.6
+ react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1)
+
+ '@rolldown/binding-android-arm64@1.0.2':
optional: true
- '@rolldown/binding-darwin-arm64@1.0.0-rc.12':
+ '@rolldown/binding-darwin-arm64@1.0.2':
optional: true
- '@rolldown/binding-darwin-x64@1.0.0-rc.12':
+ '@rolldown/binding-darwin-x64@1.0.2':
optional: true
- '@rolldown/binding-freebsd-x64@1.0.0-rc.12':
+ '@rolldown/binding-freebsd-x64@1.0.2':
optional: true
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12':
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.2':
optional: true
- '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12':
+ '@rolldown/binding-linux-arm64-gnu@1.0.2':
optional: true
- '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12':
+ '@rolldown/binding-linux-arm64-musl@1.0.2':
optional: true
- '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12':
+ '@rolldown/binding-linux-ppc64-gnu@1.0.2':
optional: true
- '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12':
+ '@rolldown/binding-linux-s390x-gnu@1.0.2':
optional: true
- '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12':
+ '@rolldown/binding-linux-x64-gnu@1.0.2':
optional: true
- '@rolldown/binding-linux-x64-musl@1.0.0-rc.12':
+ '@rolldown/binding-linux-x64-musl@1.0.2':
optional: true
- '@rolldown/binding-openharmony-arm64@1.0.0-rc.12':
+ '@rolldown/binding-openharmony-arm64@1.0.2':
optional: true
- '@rolldown/binding-wasm32-wasi@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)':
+ '@rolldown/binding-wasm32-wasi@1.0.2':
dependencies:
- '@napi-rs/wasm-runtime': 1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
+ '@emnapi/core': 1.10.0
+ '@emnapi/runtime': 1.10.0
+ '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
optional: true
- '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12':
+ '@rolldown/binding-win32-arm64-msvc@1.0.2':
optional: true
- '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12':
+ '@rolldown/binding-win32-x64-msvc@1.0.2':
optional: true
- '@rolldown/pluginutils@1.0.0-rc.12': {}
+ '@rolldown/pluginutils@1.0.1': {}
- '@rolldown/pluginutils@1.0.0-rc.7': {}
+ '@standard-schema/spec@1.1.0': {}
- '@tailwindcss/node@4.2.2':
+ '@standard-schema/utils@0.3.0': {}
+
+ '@tailwindcss/node@4.3.0':
dependencies:
'@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.20.1
- jiti: 2.6.1
+ enhanced-resolve: 5.22.0
+ jiti: 2.7.0
lightningcss: 1.32.0
magic-string: 0.30.21
source-map-js: 1.2.1
- tailwindcss: 4.2.2
+ tailwindcss: 4.3.0
- '@tailwindcss/oxide-android-arm64@4.2.2':
+ '@tailwindcss/oxide-android-arm64@4.3.0':
optional: true
- '@tailwindcss/oxide-darwin-arm64@4.2.2':
+ '@tailwindcss/oxide-darwin-arm64@4.3.0':
optional: true
- '@tailwindcss/oxide-darwin-x64@4.2.2':
+ '@tailwindcss/oxide-darwin-x64@4.3.0':
optional: true
- '@tailwindcss/oxide-freebsd-x64@4.2.2':
+ '@tailwindcss/oxide-freebsd-x64@4.3.0':
optional: true
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2':
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0':
optional: true
- '@tailwindcss/oxide-linux-arm64-gnu@4.2.2':
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.0':
optional: true
- '@tailwindcss/oxide-linux-arm64-musl@4.2.2':
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.0':
optional: true
- '@tailwindcss/oxide-linux-x64-gnu@4.2.2':
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.0':
optional: true
- '@tailwindcss/oxide-linux-x64-musl@4.2.2':
+ '@tailwindcss/oxide-linux-x64-musl@4.3.0':
optional: true
- '@tailwindcss/oxide-wasm32-wasi@4.2.2':
+ '@tailwindcss/oxide-wasm32-wasi@4.3.0':
optional: true
- '@tailwindcss/oxide-win32-arm64-msvc@4.2.2':
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.0':
optional: true
- '@tailwindcss/oxide-win32-x64-msvc@4.2.2':
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.0':
optional: true
- '@tailwindcss/oxide@4.2.2':
+ '@tailwindcss/oxide@4.3.0':
optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.2.2
- '@tailwindcss/oxide-darwin-arm64': 4.2.2
- '@tailwindcss/oxide-darwin-x64': 4.2.2
- '@tailwindcss/oxide-freebsd-x64': 4.2.2
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2
- '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2
- '@tailwindcss/oxide-linux-arm64-musl': 4.2.2
- '@tailwindcss/oxide-linux-x64-gnu': 4.2.2
- '@tailwindcss/oxide-linux-x64-musl': 4.2.2
- '@tailwindcss/oxide-wasm32-wasi': 4.2.2
- '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2
- '@tailwindcss/oxide-win32-x64-msvc': 4.2.2
+ '@tailwindcss/oxide-android-arm64': 4.3.0
+ '@tailwindcss/oxide-darwin-arm64': 4.3.0
+ '@tailwindcss/oxide-darwin-x64': 4.3.0
+ '@tailwindcss/oxide-freebsd-x64': 4.3.0
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0
+ '@tailwindcss/oxide-linux-arm64-musl': 4.3.0
+ '@tailwindcss/oxide-linux-x64-gnu': 4.3.0
+ '@tailwindcss/oxide-linux-x64-musl': 4.3.0
+ '@tailwindcss/oxide-wasm32-wasi': 4.3.0
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0
+ '@tailwindcss/oxide-win32-x64-msvc': 4.3.0
- '@tailwindcss/postcss@4.2.2':
+ '@tailwindcss/postcss@4.3.0':
dependencies:
'@alloc/quick-lru': 5.2.0
- '@tailwindcss/node': 4.2.2
- '@tailwindcss/oxide': 4.2.2
- postcss: 8.5.8
- tailwindcss: 4.2.2
+ '@tailwindcss/node': 4.3.0
+ '@tailwindcss/oxide': 4.3.0
+ postcss: 8.5.15
+ tailwindcss: 4.3.0
- '@tanstack/query-core@5.66.4': {}
+ '@tanstack/query-core@5.100.14': {}
- '@tanstack/query-devtools@5.65.0': {}
+ '@tanstack/query-devtools@5.100.14': {}
- '@tanstack/react-query-devtools@5.66.7(@tanstack/react-query@5.66.7(react@19.0.0))(react@19.0.0)':
+ '@tanstack/react-query-devtools@5.100.14(@tanstack/react-query@5.100.14(react@19.2.6))(react@19.2.6)':
dependencies:
- '@tanstack/query-devtools': 5.65.0
- '@tanstack/react-query': 5.66.7(react@19.0.0)
- react: 19.0.0
+ '@tanstack/query-devtools': 5.100.14
+ '@tanstack/react-query': 5.100.14(react@19.2.6)
+ react: 19.2.6
- '@tanstack/react-query@5.66.7(react@19.0.0)':
+ '@tanstack/react-query@5.100.14(react@19.2.6)':
dependencies:
- '@tanstack/query-core': 5.66.4
- react: 19.0.0
+ '@tanstack/query-core': 5.100.14
+ react: 19.2.6
- '@tanstack/react-table@8.21.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ '@tanstack/react-table@8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
- '@tanstack/table-core': 8.21.2
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@tanstack/table-core': 8.21.3
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
- '@tanstack/table-core@8.21.2': {}
+ '@tanstack/table-core@8.21.3': {}
- '@tybys/wasm-util@0.10.1':
+ '@tybys/wasm-util@0.10.2':
dependencies:
tslib: 2.8.1
optional: true
@@ -2548,24 +2326,26 @@ snapshots:
'@types/geojson@7946.0.16': {}
- '@types/luxon@3.4.2': {}
+ '@types/luxon@3.7.1': {}
- '@types/node@22.13.4':
+ '@types/node@25.9.1':
dependencies:
- undici-types: 6.20.0
+ undici-types: 7.24.6
- '@types/react-dom@19.0.4(@types/react@19.0.10)':
+ '@types/react-dom@19.2.3(@types/react@19.2.15)':
dependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- '@types/react@19.0.10':
+ '@types/react@19.2.15':
dependencies:
csstype: 3.2.3
- '@vitejs/plugin-react@6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.13.4)(jiti@2.6.1))':
+ '@types/use-sync-external-store@0.0.6': {}
+
+ '@vitejs/plugin-react@6.0.2(vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0))':
dependencies:
- '@rolldown/pluginutils': 1.0.0-rc.7
- vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.13.4)(jiti@2.6.1)
+ '@rolldown/pluginutils': 1.0.1
+ vite: 8.0.14(@types/node@25.9.1)(jiti@2.7.0)
aria-hidden@1.2.6:
dependencies:
@@ -2577,21 +2357,21 @@ snapshots:
clsx@2.1.1: {}
- cmdk@1.1.1(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
- '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- '@radix-ui/react-id': 1.1.1(@types/react@19.0.10)(react@19.0.0)
- '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.0.4(@types/react@19.0.10))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6)
+ '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
cookie@1.1.1: {}
- country-flag-icons@1.5.18: {}
+ country-flag-icons@1.6.17: {}
csstype@3.2.3: {}
@@ -2637,7 +2417,7 @@ snapshots:
d3-timer@3.0.1: {}
- dayjs@1.11.13: {}
+ dayjs@1.11.20: {}
decimal.js-light@2.5.1: {}
@@ -2647,39 +2427,34 @@ snapshots:
diacritics@1.3.0: {}
- dom-helpers@5.2.1:
- dependencies:
- '@babel/runtime': 7.29.2
- csstype: 3.2.3
-
- enhanced-resolve@5.20.1:
+ enhanced-resolve@5.22.0:
dependencies:
graceful-fs: 4.2.11
- tapable: 2.3.2
+ tapable: 2.3.3
- eventemitter3@4.0.7: {}
+ es-toolkit@1.46.1: {}
- fast-equals@5.4.0: {}
+ eventemitter3@5.0.4: {}
fdir@6.5.0(picomatch@4.0.4):
optionalDependencies:
picomatch: 4.0.4
- framer-motion@12.23.26(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ framer-motion@12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
- motion-dom: 12.38.0
- motion-utils: 12.36.0
+ motion-dom: 12.40.0
+ motion-utils: 12.39.0
tslib: 2.8.1
optionalDependencies:
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
fsevents@2.3.3:
optional: true
get-nonce@1.0.1: {}
- globals@15.15.0: {}
+ globals@17.6.0: {}
graceful-fs@4.2.11: {}
@@ -2691,17 +2466,17 @@ snapshots:
dependencies:
diacritics: 1.3.0
- i18next@24.2.2(typescript@5.6.3):
- dependencies:
- '@babel/runtime': 7.29.2
+ i18next@26.2.0(typescript@6.0.3):
optionalDependencies:
- typescript: 5.6.3
+ typescript: 6.0.3
+
+ immer@10.2.0: {}
+
+ immer@11.1.8: {}
internmap@2.0.3: {}
- jiti@2.6.1: {}
-
- js-tokens@4.0.0: {}
+ jiti@2.7.0: {}
lightningcss-android-arm64@1.32.0:
optional: true
@@ -2752,223 +2527,207 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.32.0
lightningcss-win32-x64-msvc: 1.32.0
- lodash@4.18.1: {}
-
- loose-envify@1.4.0:
+ lucide-react@1.16.0(react@19.2.6):
dependencies:
- js-tokens: 4.0.0
+ react: 19.2.6
- lucide-react@0.460.0(react@19.0.0):
- dependencies:
- react: 19.0.0
-
- luxon@3.5.0: {}
+ luxon@3.7.2: {}
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- motion-dom@12.38.0:
+ motion-dom@12.40.0:
dependencies:
- motion-utils: 12.36.0
+ motion-utils: 12.39.0
- motion-utils@12.36.0: {}
+ motion-utils@12.39.0: {}
- nanoid@3.3.11: {}
-
- object-assign@4.1.1: {}
+ nanoid@3.3.12: {}
picocolors@1.1.1: {}
picomatch@4.0.4: {}
- postcss@8.5.3:
+ postcss@8.5.15:
dependencies:
- nanoid: 3.3.11
+ nanoid: 3.3.12
picocolors: 1.1.1
source-map-js: 1.2.1
- postcss@8.5.8:
+ react-dom@19.2.6(react@19.2.6):
dependencies:
- nanoid: 3.3.11
- picocolors: 1.1.1
- source-map-js: 1.2.1
+ react: 19.2.6
+ scheduler: 0.27.0
- prop-types@15.8.1:
- dependencies:
- loose-envify: 1.4.0
- object-assign: 4.1.1
- react-is: 16.13.1
-
- react-dom@19.0.0(react@19.0.0):
- dependencies:
- react: 19.0.0
- scheduler: 0.25.0
-
- react-i18next@15.4.1(i18next@24.2.2(typescript@5.6.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ react-i18next@17.0.8(i18next@26.2.0(typescript@6.0.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@6.0.3):
dependencies:
'@babel/runtime': 7.29.2
html-parse-stringify: 3.0.1
- i18next: 24.2.2(typescript@5.6.3)
- react: 19.0.0
+ i18next: 26.2.0(typescript@6.0.3)
+ react: 19.2.6
+ use-sync-external-store: 1.6.0(react@19.2.6)
optionalDependencies:
- react-dom: 19.0.0(react@19.0.0)
-
- react-is@16.13.1: {}
+ react-dom: 19.2.6(react@19.2.6)
+ typescript: 6.0.3
react-is@18.3.1: {}
- react-remove-scroll-bar@2.3.8(@types/react@19.0.10)(react@19.0.0):
+ react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1):
dependencies:
- react: 19.0.0
- react-style-singleton: 2.2.3(@types/react@19.0.10)(react@19.0.0)
+ '@types/use-sync-external-store': 0.0.6
+ react: 19.2.6
+ use-sync-external-store: 1.6.0(react@19.2.6)
+ optionalDependencies:
+ '@types/react': 19.2.15
+ redux: 5.0.1
+
+ react-remove-scroll-bar@2.3.8(@types/react@19.2.15)(react@19.2.6):
+ dependencies:
+ react: 19.2.6
+ react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6)
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- react-remove-scroll@2.7.2(@types/react@19.0.10)(react@19.0.0):
+ react-remove-scroll@2.7.2(@types/react@19.2.15)(react@19.2.6):
dependencies:
- react: 19.0.0
- react-remove-scroll-bar: 2.3.8(@types/react@19.0.10)(react@19.0.0)
- react-style-singleton: 2.2.3(@types/react@19.0.10)(react@19.0.0)
+ react: 19.2.6
+ react-remove-scroll-bar: 2.3.8(@types/react@19.2.15)(react@19.2.6)
+ react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6)
tslib: 2.8.1
- use-callback-ref: 1.3.3(@types/react@19.0.10)(react@19.0.0)
- use-sidecar: 1.1.3(@types/react@19.0.10)(react@19.0.0)
+ use-callback-ref: 1.3.3(@types/react@19.2.15)(react@19.2.6)
+ use-sidecar: 1.1.3(@types/react@19.2.15)(react@19.2.6)
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- react-router-dom@7.13.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ react-router-dom@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-router: 7.13.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
+ react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
- react-router@7.13.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
cookie: 1.1.1
- react: 19.0.0
+ react: 19.2.6
set-cookie-parser: 2.7.2
optionalDependencies:
- react-dom: 19.0.0(react@19.0.0)
+ react-dom: 19.2.6(react@19.2.6)
- react-smooth@4.0.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
- dependencies:
- fast-equals: 5.4.0
- prop-types: 15.8.1
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
- react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
-
- react-style-singleton@2.2.3(@types/react@19.0.10)(react@19.0.0):
+ react-style-singleton@2.2.3(@types/react@19.2.15)(react@19.2.6):
dependencies:
get-nonce: 1.0.1
- react: 19.0.0
+ react: 19.2.6
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
- dependencies:
- '@babel/runtime': 7.29.2
- dom-helpers: 5.2.1
- loose-envify: 1.4.0
- prop-types: 15.8.1
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react@19.2.6: {}
- react@19.0.0: {}
-
- recharts-scale@0.4.5:
- dependencies:
- decimal.js-light: 2.5.1
-
- recharts@2.15.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ recharts@3.8.1(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react-is@18.3.1)(react@19.2.6)(redux@5.0.1):
dependencies:
+ '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6)
clsx: 2.1.1
- eventemitter3: 4.0.7
- lodash: 4.18.1
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ decimal.js-light: 2.5.1
+ es-toolkit: 1.46.1
+ eventemitter3: 5.0.4
+ immer: 10.2.0
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
react-is: 18.3.1
- react-smooth: 4.0.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
- recharts-scale: 0.4.5
+ react-redux: 9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1)
+ reselect: 5.1.1
tiny-invariant: 1.3.3
- victory-vendor: 36.9.2
-
- rolldown@1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1):
- dependencies:
- '@oxc-project/types': 0.122.0
- '@rolldown/pluginutils': 1.0.0-rc.12
- optionalDependencies:
- '@rolldown/binding-android-arm64': 1.0.0-rc.12
- '@rolldown/binding-darwin-arm64': 1.0.0-rc.12
- '@rolldown/binding-darwin-x64': 1.0.0-rc.12
- '@rolldown/binding-freebsd-x64': 1.0.0-rc.12
- '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12
- '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12
- '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12
- '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12
- '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12
- '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12
- '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12
- '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12
- '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)
- '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12
- '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12
+ use-sync-external-store: 1.6.0(react@19.2.6)
+ victory-vendor: 37.3.6
transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
+ - '@types/react'
+ - redux
- scheduler@0.25.0: {}
+ redux-thunk@3.1.0(redux@5.0.1):
+ dependencies:
+ redux: 5.0.1
+
+ redux@5.0.1: {}
+
+ reselect@5.1.1: {}
+
+ rolldown@1.0.2:
+ dependencies:
+ '@oxc-project/types': 0.132.0
+ '@rolldown/pluginutils': 1.0.1
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.0.2
+ '@rolldown/binding-darwin-arm64': 1.0.2
+ '@rolldown/binding-darwin-x64': 1.0.2
+ '@rolldown/binding-freebsd-x64': 1.0.2
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.2
+ '@rolldown/binding-linux-arm64-gnu': 1.0.2
+ '@rolldown/binding-linux-arm64-musl': 1.0.2
+ '@rolldown/binding-linux-ppc64-gnu': 1.0.2
+ '@rolldown/binding-linux-s390x-gnu': 1.0.2
+ '@rolldown/binding-linux-x64-gnu': 1.0.2
+ '@rolldown/binding-linux-x64-musl': 1.0.2
+ '@rolldown/binding-openharmony-arm64': 1.0.2
+ '@rolldown/binding-wasm32-wasi': 1.0.2
+ '@rolldown/binding-win32-arm64-msvc': 1.0.2
+ '@rolldown/binding-win32-x64-msvc': 1.0.2
+
+ scheduler@0.27.0: {}
set-cookie-parser@2.7.2: {}
- sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
+ sonner@2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6):
dependencies:
- react: 19.0.0
- react-dom: 19.0.0(react@19.0.0)
+ react: 19.2.6
+ react-dom: 19.2.6(react@19.2.6)
source-map-js@1.2.1: {}
- tailwind-merge@2.6.0: {}
+ tailwind-merge@3.6.0: {}
- tailwindcss-animate@1.0.7(tailwindcss@4.2.2):
+ tailwindcss-animate@1.0.7(tailwindcss@4.3.0):
dependencies:
- tailwindcss: 4.2.2
+ tailwindcss: 4.3.0
- tailwindcss@4.2.2: {}
+ tailwindcss@4.3.0: {}
- tapable@2.3.2: {}
+ tapable@2.3.3: {}
tiny-invariant@1.3.3: {}
- tinyglobby@0.2.15:
+ tinyglobby@0.2.16:
dependencies:
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
tslib@2.8.1: {}
- typescript@5.6.3: {}
+ typescript@6.0.3: {}
- undici-types@6.20.0: {}
+ undici-types@7.24.6: {}
- use-callback-ref@1.3.3(@types/react@19.0.10)(react@19.0.0):
+ use-callback-ref@1.3.3(@types/react@19.2.15)(react@19.2.6):
dependencies:
- react: 19.0.0
+ react: 19.2.6
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- use-sidecar@1.1.3(@types/react@19.0.10)(react@19.0.0):
+ use-sidecar@1.1.3(@types/react@19.2.15)(react@19.2.6):
dependencies:
detect-node-es: 1.1.0
- react: 19.0.0
+ react: 19.2.6
tslib: 2.8.1
optionalDependencies:
- '@types/react': 19.0.10
+ '@types/react': 19.2.15
- victory-vendor@36.9.2:
+ use-sync-external-store@1.6.0(react@19.2.6):
+ dependencies:
+ react: 19.2.6
+
+ victory-vendor@37.3.6:
dependencies:
'@types/d3-array': 3.2.2
'@types/d3-ease': 3.0.2
@@ -2985,19 +2744,16 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@22.13.4)(jiti@2.6.1):
+ vite@8.0.14(@types/node@25.9.1)(jiti@2.7.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
- postcss: 8.5.8
- rolldown: 1.0.0-rc.12(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)
- tinyglobby: 0.2.15
+ postcss: 8.5.15
+ rolldown: 1.0.2
+ tinyglobby: 0.2.16
optionalDependencies:
- '@types/node': 22.13.4
+ '@types/node': 25.9.1
fsevents: 2.3.3
- jiti: 2.6.1
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
+ jiti: 2.7.0
void-elements@3.1.0: {}
diff --git a/vite.config.ts b/vite.config.ts
index 261c0f7..f51d39d 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,7 @@
import { execSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
-import react from '@vitejs/plugin-react'
+import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// Get git commit hash
From 4b0106c011b11b5c5191af964b2928351f419549 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Mon, 25 May 2026 01:42:49 +0800
Subject: [PATCH 08/64] fix: simplify className usage for icons in Server
component
---
src/pages/Server.tsx | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index 72f8221..42f1361 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -317,7 +317,7 @@ export default function Servers() {
},
)}
>
-
+
Date: Mon, 25 May 2026 01:57:50 +0800
Subject: [PATCH 09/64] fix: enhance sorting functionality by adding forced
sort type and order handling
---
src/context/sort-provider.tsx | 62 ++++++++++++++++++++++++++++++++---
src/hooks/use-background.ts | 2 ++
tsconfig.app.json | 3 +-
3 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/src/context/sort-provider.tsx b/src/context/sort-provider.tsx
index bff228b..1e6aa2e 100644
--- a/src/context/sort-provider.tsx
+++ b/src/context/sort-provider.tsx
@@ -1,10 +1,64 @@
-import { type ReactNode, useState } from "react";
+import { type ReactNode, useEffect, useState } from "react";
-import { SortContext, type SortOrder, type SortType } from "./sort-context";
+import {
+ SORT_ORDERS,
+ SORT_TYPES,
+ SortContext,
+ type SortOrder,
+ type SortType,
+} from "./sort-context";
+
+const getForcedSortType = (): SortType | undefined => {
+ const forcedSortType = window.ForceSortType;
+ if (forcedSortType && SORT_TYPES.includes(forcedSortType as SortType)) {
+ return forcedSortType as SortType;
+ }
+ return undefined;
+};
+
+const getForcedSortOrder = (): SortOrder | undefined => {
+ const forcedSortOrder = window.ForceSortOrder;
+ if (forcedSortOrder && SORT_ORDERS.includes(forcedSortOrder as SortOrder)) {
+ return forcedSortOrder as SortOrder;
+ }
+ return undefined;
+};
export function SortProvider({ children }: { children: ReactNode }) {
- const [sortType, setSortType] = useState("default");
- const [sortOrder, setSortOrder] = useState("desc");
+ const [sortType, setSortType] = useState(
+ () => getForcedSortType() || "default",
+ );
+ const [sortOrder, setSortOrder] = useState(
+ () => getForcedSortOrder() || "desc",
+ );
+
+ useEffect(() => {
+ const applyForcedSort = () => {
+ const forcedSortType = getForcedSortType();
+ const forcedSortOrder = getForcedSortOrder();
+ if (forcedSortType) {
+ setSortType(forcedSortType);
+ }
+ if (forcedSortOrder) {
+ setSortOrder(forcedSortOrder);
+ }
+ };
+
+ applyForcedSort();
+
+ let retryCount = 0;
+ const intervalId = window.setInterval(() => {
+ retryCount += 1;
+ if (window.ForceSortType || window.ForceSortOrder || retryCount >= 50) {
+ applyForcedSort();
+ window.clearInterval(intervalId);
+ }
+ }, 100);
+
+ return () => {
+ window.clearInterval(intervalId);
+ };
+ }, []);
return (
Date: Tue, 26 May 2026 01:34:02 +0800
Subject: [PATCH 10/64] fix: support per-server max/from/to in cycle transfer
stats (#64)
* Initial plan
* fix: support per-server max/from/to values in cycle transfer stats
When the Nezha backend has multiple transfer rules within one alert rule,
the API may return per-server max values (as a map) instead of a single
max value. Update the TypeScript interface and CycleTransferStats component
to handle both formats:
- Single value (number/string): used for all servers (current behavior)
- Per-server map ({[serverId]: value}): uses the correct value per server
Fixes #63
Agent-Logs-Url: https://github.com/hamster1963/nezha-dash-v2/sessions/88f98dad-c2eb-4728-ac98-e02a95d5144d
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
* fix: update schema version in biome.json and improve null checks in components
* chore: auto-fix linting and formatting issues
* fix: guard null/zero in CycleTransferStats per-server map lookups
Agent-Logs-Url: https://github.com/hamster1963/nezha-dash-v2/sessions/2fb2306b-8011-487d-b284-9768778db8c3
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: hamster1963 <71394853+hamster1963@users.noreply.github.com>
Co-authored-by: hamster1963 <1410514192@qq.com>
---
biome.json | 2 +-
bun.lock | 594 +++++++++++---------------
index.html | 2 +-
src/components/CycleTransferStats.tsx | 29 +-
src/components/PlanInfo.tsx | 2 +-
src/components/ServerFlag.tsx | 2 +-
src/components/billingInfo.tsx | 2 +-
src/components/ui/accordion.tsx | 2 +-
src/components/ui/card.tsx | 8 +-
src/components/ui/chart.tsx | 4 +-
src/components/ui/command.tsx | 6 +-
src/components/ui/dialog.tsx | 12 +-
src/components/ui/dropdown-menu.tsx | 14 +-
src/components/ui/popover.tsx | 2 +-
src/components/ui/select.tsx | 12 +-
src/components/ui/table.tsx | 6 +-
src/components/ui/tooltip.tsx | 2 +-
src/types/nezha-api.ts | 8 +-
18 files changed, 308 insertions(+), 401 deletions(-)
diff --git a/biome.json b/biome.json
index 4f42c6f..7103e4d 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
diff --git a/bun.lock b/bun.lock
index a9a33b1..4f92a66 100644
--- a/bun.lock
+++ b/bun.lock
@@ -5,134 +5,88 @@
"": {
"name": "nazha-dashboard-vite",
"dependencies": {
- "@fontsource/inter": "5.1.1",
+ "@fontsource/inter": "5.2.8",
"@heroicons/react": "2.2.0",
- "@radix-ui/react-accordion": "1.2.3",
- "@radix-ui/react-checkbox": "1.1.4",
+ "@radix-ui/react-accordion": "1.2.12",
+ "@radix-ui/react-checkbox": "1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
- "@radix-ui/react-dropdown-menu": "2.1.6",
- "@radix-ui/react-label": "2.1.2",
- "@radix-ui/react-popover": "1.1.6",
- "@radix-ui/react-progress": "1.1.2",
- "@radix-ui/react-select": "2.1.6",
- "@radix-ui/react-separator": "1.1.2",
- "@radix-ui/react-slot": "1.1.2",
- "@radix-ui/react-switch": "1.1.3",
- "@radix-ui/react-tooltip": "1.1.8",
- "@tanstack/react-query": "5.66.7",
- "@tanstack/react-query-devtools": "5.66.7",
- "@tanstack/react-table": "8.21.2",
+ "@radix-ui/react-dropdown-menu": "2.1.16",
+ "@radix-ui/react-label": "2.1.8",
+ "@radix-ui/react-popover": "1.1.15",
+ "@radix-ui/react-progress": "1.1.8",
+ "@radix-ui/react-select": "2.2.6",
+ "@radix-ui/react-separator": "1.1.8",
+ "@radix-ui/react-slot": "1.2.4",
+ "@radix-ui/react-switch": "1.2.6",
+ "@radix-ui/react-tooltip": "1.2.8",
+ "@tanstack/react-query": "5.100.14",
+ "@tanstack/react-query-devtools": "5.100.14",
+ "@tanstack/react-table": "8.21.3",
"@types/d3-geo": "3.1.0",
- "@types/luxon": "3.4.2",
+ "@types/luxon": "3.7.1",
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"cmdk": "1.1.1",
- "country-flag-icons": "1.5.18",
+ "country-flag-icons": "1.6.17",
"d3-geo": "3.1.1",
- "dayjs": "1.11.13",
- "framer-motion": "12.23.26",
+ "dayjs": "1.11.20",
+ "framer-motion": "12.40.0",
"i18n-iso-countries": "7.14.0",
- "i18next": "24.2.2",
- "lucide-react": "0.460.0",
- "luxon": "3.5.0",
- "react": "19.0.0",
- "react-dom": "19.0.0",
- "react-i18next": "15.4.1",
- "react-router-dom": "^7.13.0",
- "recharts": "2.15.1",
- "sonner": "1.7.4",
- "tailwind-merge": "2.6.0",
+ "i18next": "26.2.0",
+ "lucide-react": "1.16.0",
+ "luxon": "3.7.2",
+ "react": "19.2.6",
+ "react-dom": "19.2.6",
+ "react-i18next": "17.0.8",
+ "react-router-dom": "^7.15.1",
+ "recharts": "3.8.1",
+ "sonner": "2.0.7",
+ "tailwind-merge": "3.6.0",
"tailwindcss-animate": "^1.0.7",
},
"devDependencies": {
- "@biomejs/biome": "2.3.10",
- "@tailwindcss/postcss": "^4.1.18",
- "@types/node": "22.13.4",
- "@types/react": "19.0.10",
- "@types/react-dom": "19.0.4",
- "@vitejs/plugin-react-swc": "3.8.0",
- "globals": "15.15.0",
- "postcss": "8.5.3",
- "tailwindcss": "^4.1.18",
- "typescript": "~5.6.3",
- "vite": "6.4.1",
+ "@biomejs/biome": "2.4.15",
+ "@tailwindcss/postcss": "^4.3.0",
+ "@types/node": "25.9.1",
+ "@types/react": "19.2.15",
+ "@types/react-dom": "19.2.3",
+ "@vitejs/plugin-react": "^6.0.2",
+ "globals": "17.6.0",
+ "postcss": "8.5.15",
+ "tailwindcss": "^4.3.0",
+ "typescript": "~6.0.3",
+ "vite": "8.0.14",
},
},
},
"packages": {
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
- "@babel/runtime": ["@babel/runtime@7.26.0", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw=="],
+ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
- "@biomejs/biome": ["@biomejs/biome@2.3.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.10", "@biomejs/cli-darwin-x64": "2.3.10", "@biomejs/cli-linux-arm64": "2.3.10", "@biomejs/cli-linux-arm64-musl": "2.3.10", "@biomejs/cli-linux-x64": "2.3.10", "@biomejs/cli-linux-x64-musl": "2.3.10", "@biomejs/cli-win32-arm64": "2.3.10", "@biomejs/cli-win32-x64": "2.3.10" }, "bin": { "biome": "bin/biome" } }, "sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ=="],
+ "@biomejs/biome": ["@biomejs/biome@2.4.15", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.15", "@biomejs/cli-darwin-x64": "2.4.15", "@biomejs/cli-linux-arm64": "2.4.15", "@biomejs/cli-linux-arm64-musl": "2.4.15", "@biomejs/cli-linux-x64": "2.4.15", "@biomejs/cli-linux-x64-musl": "2.4.15", "@biomejs/cli-win32-arm64": "2.4.15", "@biomejs/cli-win32-x64": "2.4.15" }, "bin": { "biome": "bin/biome" } }, "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw=="],
- "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w=="],
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg=="],
- "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg=="],
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ=="],
- "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA=="],
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug=="],
- "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A=="],
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ=="],
- "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.10", "", { "os": "linux", "cpu": "x64" }, "sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw=="],
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g=="],
- "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g=="],
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.15", "", { "os": "linux", "cpu": "x64" }, "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w=="],
- "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ=="],
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w=="],
- "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.10", "", { "os": "win32", "cpu": "x64" }, "sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ=="],
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.15", "", { "os": "win32", "cpu": "x64" }, "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ=="],
- "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
+ "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
- "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
+ "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
- "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
-
- "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
-
- "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
-
- "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
-
- "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
-
- "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
-
- "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
-
- "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
-
- "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
-
- "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
-
- "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
-
- "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
-
- "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
-
- "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
-
- "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
-
- "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
-
- "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
-
- "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
-
- "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
-
- "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
-
- "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
-
- "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
-
- "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
-
- "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
+ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@floating-ui/core": ["@floating-ui/core@1.6.8", "", { "dependencies": { "@floating-ui/utils": "^0.2.8" } }, "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA=="],
@@ -142,7 +96,7 @@
"@floating-ui/utils": ["@floating-ui/utils@0.2.8", "", {}, "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig=="],
- "@fontsource/inter": ["@fontsource/inter@5.1.1", "", {}, "sha512-weN3E+rq0Xb3Z93VHJ+Rc7WOQX9ETJPTAJ+gDcaMHtjft67L58sfS65rAjC5tZUXQ2FdZ/V1/sSzCwZ6v05kJw=="],
+ "@fontsource/inter": ["@fontsource/inter@5.2.8", "", {}, "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg=="],
"@heroicons/react": ["@heroicons/react@2.2.0", "", { "peerDependencies": { "react": ">= 16 || ^19.0.0-rc" } }, "sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ=="],
@@ -158,203 +112,171 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
- "@radix-ui/number": ["@radix-ui/number@1.1.0", "", {}, "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="],
+ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="],
- "@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
+ "@oxc-project/types": ["@oxc-project/types@0.132.0", "", {}, "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ=="],
- "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collapsible": "1.1.3", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A=="],
+ "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
- "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg=="],
+ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
- "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.1.4", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw=="],
+ "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
- "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw=="],
+ "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
- "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw=="],
+ "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw=="],
- "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
+ "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="],
- "@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
+ "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="],
+
+ "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
+
+ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
"@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="],
- "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
+ "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="],
"@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="],
- "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-menu": "2.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA=="],
+ "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="],
"@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="],
"@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="],
- "@radix-ui/react-id": ["@radix-ui/react-id@1.1.0", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA=="],
+ "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
- "@radix-ui/react-label": ["@radix-ui/react-label@2.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zo1uGMTaNlHehDyFQcDZXRJhUPDuukcnHz0/jnrup0JA6qL+AFpAnty+7VKa9esuU5xTblAZzTGYJKSKaBxBhw=="],
+ "@radix-ui/react-label": ["@radix-ui/react-label@2.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A=="],
- "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg=="],
+ "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
- "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg=="],
+ "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="],
- "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.2", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-rect": "1.1.0", "@radix-ui/react-use-size": "1.1.0", "@radix-ui/rect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA=="],
+ "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
- "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
+ "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
- "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
+ "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
- "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.2", "", { "dependencies": { "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-u1IgJFQ4zNAUTjGdDL5dcl/U8ntOR6jsnhxKb5RKp5Ozwl88xKR9EqRZOe/Mk8tnx0x5tNUe2F+MzsyjqMg0MA=="],
+ "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.8", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA=="],
- "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw=="],
+ "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
- "@radix-ui/react-select": ["@radix-ui/react-select@2.1.6", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg=="],
+ "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="],
- "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ=="],
+ "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g=="],
- "@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
+ "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="],
- "@radix-ui/react-switch": ["@radix-ui/react-switch@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1nc+vjEOQkJVsJtWPSiISGT6OKm4SiOdjMo+/icLxo2G4vxz1GntC5MzfL4v8ey9OEfw787QCD1y3mUv0NiFEQ=="],
+ "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
- "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-popper": "1.2.2", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-visually-hidden": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA=="],
+ "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
- "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
+ "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
- "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
+ "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="],
- "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
+ "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
- "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og=="],
+ "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
- "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.0", "", { "dependencies": { "@radix-ui/rect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ=="],
+ "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="],
- "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.0", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw=="],
+ "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
- "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q=="],
+ "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="],
- "@radix-ui/rect": ["@radix-ui/rect@1.1.0", "", {}, "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="],
+ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
- "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="],
+ "@reduxjs/toolkit": ["@reduxjs/toolkit@2.12.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^11.0.0", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw=="],
- "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="],
+ "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.2", "", { "os": "android", "cpu": "arm64" }, "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ=="],
- "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="],
+ "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w=="],
- "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="],
+ "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA=="],
- "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="],
+ "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA=="],
- "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="],
+ "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w=="],
- "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="],
+ "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig=="],
- "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="],
+ "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw=="],
- "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="],
+ "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA=="],
- "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="],
+ "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ=="],
- "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="],
+ "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ=="],
- "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="],
+ "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw=="],
- "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="],
+ "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w=="],
- "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="],
+ "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.2", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ=="],
- "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="],
+ "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A=="],
- "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="],
+ "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ=="],
- "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="],
+ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
- "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="],
+ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
- "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="],
+ "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
- "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="],
+ "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.21.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="],
- "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="],
+ "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="],
- "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="],
+ "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="],
- "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="],
+ "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="],
- "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="],
+ "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="],
- "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="],
+ "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="],
- "@swc/core": ["@swc/core@1.10.15", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.17" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.10.15", "@swc/core-darwin-x64": "1.10.15", "@swc/core-linux-arm-gnueabihf": "1.10.15", "@swc/core-linux-arm64-gnu": "1.10.15", "@swc/core-linux-arm64-musl": "1.10.15", "@swc/core-linux-x64-gnu": "1.10.15", "@swc/core-linux-x64-musl": "1.10.15", "@swc/core-win32-arm64-msvc": "1.10.15", "@swc/core-win32-ia32-msvc": "1.10.15", "@swc/core-win32-x64-msvc": "1.10.15" }, "peerDependencies": { "@swc/helpers": "*" }, "optionalPeers": ["@swc/helpers"] }, "sha512-/iFeQuNaGdK7mfJbQcObhAhsMqLT7qgMYl7jX2GEIO+VDTejESpzAyKwaMeYXExN8D6e5BRHBCe7M5YlsuzjDA=="],
+ "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="],
- "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.10.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zFdZ6/yHqMCPk7OhLFqHy/MQ1EqJhcZMpNHd1gXYT7VRU3FaqvvKETrUlG3VYl65McPC7AhMRfXPyJ0JO/jARQ=="],
+ "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="],
- "@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.10.15", "", { "os": "darwin", "cpu": "x64" }, "sha512-8g4yiQwbr8fxOOjKXdot0dEkE5zgE8uNZudLy/ZyAhiwiZ8pbJ8/wVrDOu6dqbX7FBXAoDnvZ7fwN1jk4C8jdA=="],
+ "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="],
- "@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.10.15", "", { "os": "linux", "cpu": "arm" }, "sha512-rl+eVOltl2+7WXOnvmWBpMgh6aO13G5x0U0g8hjwlmD6ku3Y9iRcThpOhm7IytMEarUp5pQxItNoPq+VUGjVHg=="],
+ "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="],
- "@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.10.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-qxWEQeyAJMWJqjaN4hi58WMpPdt3Tn0biSK9CYRegQtvZWCbewr6v2agtSu5AZ2rudeH6OfCWAMDQQeSgn6PJQ=="],
+ "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="],
- "@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.10.15", "", { "os": "linux", "cpu": "arm64" }, "sha512-QcELd9/+HjZx0WCxRrKcyKGWTiQ0485kFb5w8waxcSNd0d9Lgk4EFfWWVyvIb5gIHpDQmhrgzI/yRaWQX4YSZQ=="],
+ "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="],
- "@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.10.15", "", { "os": "linux", "cpu": "x64" }, "sha512-S1+ZEEn3+a/MiMeQqQypbwTGoBG8/sPoCvpNbk+uValyygT+jSn3U0xVr45FbukpmMB+NhBMqfedMLqKA0QnJA=="],
+ "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="],
- "@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.10.15", "", { "os": "linux", "cpu": "x64" }, "sha512-qW+H9g/2zTJ4jP7NDw4VAALY0ZlNEKzYsEoSj/HKi7k3tYEHjMzsxjfsY9I8WZCft23bBdV3RTCPoxCshaj1CQ=="],
+ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="],
- "@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.10.15", "", { "os": "win32", "cpu": "arm64" }, "sha512-AhRB11aA6LxjIqut+mg7qsu/7soQDmbK6MKR9nP3hgBszpqtXbRba58lr24xIbBCMr+dpo6kgEapWt+t5Po6Zg=="],
+ "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.0", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "postcss": "^8.5.10", "tailwindcss": "4.3.0" } }, "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w=="],
- "@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.10.15", "", { "os": "win32", "cpu": "ia32" }, "sha512-UGdh430TQwbDn6KjgvRTg1fO022sbQ4yCCHUev0+5B8uoBwi9a89qAz3emy2m56C8TXxUoihW9Y9OMfaRwPXUw=="],
+ "@tanstack/query-core": ["@tanstack/query-core@5.100.14", "", {}, "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew=="],
- "@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.10.15", "", { "os": "win32", "cpu": "x64" }, "sha512-XJzBCqO1m929qbJsOG7FZXQWX26TnEoMctS3QjuCoyBmkHxxQmZsy78KjMes1aomTcKHCyFYgrRGWgVmk7tT4Q=="],
+ "@tanstack/query-devtools": ["@tanstack/query-devtools@5.100.14", "", {}, "sha512-g96SmSSQecYTYcyuAMRXr895GplJv01UGt7qttQWPOUyZ5EGz5tbRc589bMc2m5BsPFD6O0PCEAHdbDYNP6UBw=="],
- "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
+ "@tanstack/react-query": ["@tanstack/react-query@5.100.14", "", { "dependencies": { "@tanstack/query-core": "5.100.14" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw=="],
- "@swc/types": ["@swc/types@0.1.17", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ=="],
+ "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.100.14", "", { "dependencies": { "@tanstack/query-devtools": "5.100.14" }, "peerDependencies": { "@tanstack/react-query": "^5.100.14", "react": "^18 || ^19" } }, "sha512-JkP5VDgKOw3t/QSA1OABRHEqx8BuNs5MfvZRooNqdvN57SzTuGq3fKR1a2IH5rqa5HDLUm+FOXUEnB9ueHiLzg=="],
- "@tailwindcss/node": ["@tailwindcss/node@4.1.18", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.1", "lightningcss": "1.30.2", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.1.18" } }, "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ=="],
+ "@tanstack/react-table": ["@tanstack/react-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww=="],
- "@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.18", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.18", "@tailwindcss/oxide-darwin-arm64": "4.1.18", "@tailwindcss/oxide-darwin-x64": "4.1.18", "@tailwindcss/oxide-freebsd-x64": "4.1.18", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", "@tailwindcss/oxide-linux-x64-musl": "4.1.18", "@tailwindcss/oxide-wasm32-wasi": "4.1.18", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" } }, "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A=="],
+ "@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
- "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.18", "", { "os": "android", "cpu": "arm64" }, "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q=="],
-
- "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.18", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A=="],
-
- "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.18", "", { "os": "darwin", "cpu": "x64" }, "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw=="],
-
- "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.18", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA=="],
-
- "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18", "", { "os": "linux", "cpu": "arm" }, "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA=="],
-
- "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw=="],
-
- "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.18", "", { "os": "linux", "cpu": "arm64" }, "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg=="],
-
- "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g=="],
-
- "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.18", "", { "os": "linux", "cpu": "x64" }, "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ=="],
-
- "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.18", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@emnapi/wasi-threads": "^1.1.0", "@napi-rs/wasm-runtime": "^1.1.0", "@tybys/wasm-util": "^0.10.1", "tslib": "^2.4.0" }, "cpu": "none" }, "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA=="],
-
- "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.18", "", { "os": "win32", "cpu": "arm64" }, "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA=="],
-
- "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.18", "", { "os": "win32", "cpu": "x64" }, "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q=="],
-
- "@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "postcss": "^8.4.41", "tailwindcss": "4.1.18" } }, "sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g=="],
-
- "@tanstack/query-core": ["@tanstack/query-core@5.66.4", "", {}, "sha512-skM/gzNX4shPkqmdTCSoHtJAPMTtmIJNS0hE+xwTTUVYwezArCT34NMermABmBVUg5Ls5aiUXEDXfqwR1oVkcA=="],
-
- "@tanstack/query-devtools": ["@tanstack/query-devtools@5.65.0", "", {}, "sha512-g5y7zc07U9D3esMdqUfTEVu9kMHoIaVBsD0+M3LPdAdD710RpTcLiNvJY1JkYXqkq9+NV+CQoemVNpQPBXVsJg=="],
-
- "@tanstack/react-query": ["@tanstack/react-query@5.66.7", "", { "dependencies": { "@tanstack/query-core": "5.66.4" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-qd3q/tUpF2K1xItfPZddk1k/8pSXnovg41XyCqJgPoyYEirMBtB0sVEVVQ/CsAOngzgWtBPXimVf4q4kM9uO6A=="],
-
- "@tanstack/react-query-devtools": ["@tanstack/react-query-devtools@5.66.7", "", { "dependencies": { "@tanstack/query-devtools": "5.65.0" }, "peerDependencies": { "@tanstack/react-query": "^5.66.7", "react": "^18 || ^19" } }, "sha512-40z4PPkz06tYIF0vwLZZIZfZxKUH4OAaBOR14blCFyYm6hlU6qc+M82mkZ+D00HcEMhV7P4XeJiEuDhFq0q9Qw=="],
-
- "@tanstack/react-table": ["@tanstack/react-table@8.21.2", "", { "dependencies": { "@tanstack/table-core": "8.21.2" }, "peerDependencies": { "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-11tNlEDTdIhMJba2RBH+ecJ9l1zgS2kjmexDPAraulc8jeNA4xocSNeyzextT0XJyASil4XsCYlJmf5jEWAtYg=="],
-
- "@tanstack/table-core": ["@tanstack/table-core@8.21.2", "", {}, "sha512-uvXk/U4cBiFMxt+p9/G7yUWI/UbHYbyghLCjlpWZ3mLeIZiUBSKcUnw9UnKkdRz7Z/N4UBuFLWQdJCjUe7HjvA=="],
+ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="],
@@ -376,19 +298,19 @@
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
- "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
-
"@types/geojson": ["@types/geojson@7946.0.14", "", {}, "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg=="],
- "@types/luxon": ["@types/luxon@3.4.2", "", {}, "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA=="],
+ "@types/luxon": ["@types/luxon@3.7.1", "", {}, "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg=="],
- "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="],
+ "@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
- "@types/react": ["@types/react@19.0.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g=="],
+ "@types/react": ["@types/react@19.2.15", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q=="],
- "@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="],
+ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
- "@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@3.8.0", "", { "dependencies": { "@swc/core": "^1.10.15" }, "peerDependencies": { "vite": "^4 || ^5 || ^6" } }, "sha512-T4sHPvS+DIqDP51ifPqa9XIRAz/kIvIi8oXcnOZZgHmMotgmmdxe/DD5tMFlt5nuIRzT0/QuiwmKlH0503Aapw=="],
+ "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
+
+ "@vitejs/plugin-react": ["@vitejs/plugin-react@6.0.2", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0" }, "peerDependencies": { "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", "babel-plugin-react-compiler": "^1.0.0", "vite": "^8.0.0" }, "optionalPeers": ["@rolldown/plugin-babel", "babel-plugin-react-compiler"] }, "sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg=="],
"aria-hidden": ["aria-hidden@1.2.4", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A=="],
@@ -400,9 +322,9 @@
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
- "country-flag-icons": ["country-flag-icons@1.5.18", "", {}, "sha512-z+Uzesi8u8IdkViqqbzzbkf3+a7WJpcET5B7sPwTg7GXqPYpVEgNlZ/FC3l8KO4mEf+mNkmzKLppKTN4PlCJEQ=="],
+ "country-flag-icons": ["country-flag-icons@1.6.17", "", {}, "sha512-Nmik0289ZVZSI3c7mJR/amg6DyY7Z59b0sTFSKayeX72mHfPzCPJygwJs2pYgQULzuAyWeCUgwAJ+Dq8OR+JFw=="],
- "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
@@ -428,7 +350,7 @@
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
- "dayjs": ["dayjs@1.11.13", "", {}, "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="],
+ "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="],
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
@@ -438,25 +360,21 @@
"diacritics": ["diacritics@1.3.0", "", {}, "sha512-wlwEkqcsaxvPJML+rDh/2iS824jbREk6DUMUKkEaSlxdYHeS43cClJtsWglvw2RfeXGm6ohKDqsXteJ5sP5enA=="],
- "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
+ "enhanced-resolve": ["enhanced-resolve@5.22.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A=="],
- "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="],
+ "es-toolkit": ["es-toolkit@1.47.0", "", {}, "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw=="],
- "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
-
- "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="],
-
- "fast-equals": ["fast-equals@5.0.1", "", {}, "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ=="],
+ "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
- "framer-motion": ["framer-motion@12.23.26", "", { "dependencies": { "motion-dom": "^12.23.23", "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA=="],
+ "framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "^12.40.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
- "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
+ "globals": ["globals@17.6.0", "", {}, "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA=="],
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
@@ -464,235 +382,183 @@
"i18n-iso-countries": ["i18n-iso-countries@7.14.0", "", { "dependencies": { "diacritics": "1.3.0" } }, "sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg=="],
- "i18next": ["i18next@24.2.2", "", { "dependencies": { "@babel/runtime": "^7.23.2" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-NE6i86lBCKRYZa5TaUDkU5S4HFgLIEJRLr3Whf2psgaxBleQ2LC1YW1Vc+SCgkAW7VEzndT6al6+CzegSUHcTQ=="],
+ "i18next": ["i18next@26.2.0", "", { "peerDependencies": { "typescript": "^5 || ^6" }, "optionalPeers": ["typescript"] }, "sha512-zwBHldHdTmwN7r6UNc7lC6GWNN+YYg3DrRSeHR5PRRBf5QnJZcYHrQc0uaU26qZeYxR7iFZD+Y315dPnKP47wA=="],
+
+ "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
- "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
+ "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
- "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
+ "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
- "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="],
+ "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
- "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="],
+ "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
- "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="],
+ "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
- "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="],
+ "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
- "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="],
+ "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
- "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="],
+ "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
- "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="],
+ "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
- "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="],
+ "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
- "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="],
+ "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
- "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="],
+ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
- "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
+ "lucide-react": ["lucide-react@1.16.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ=="],
- "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
-
- "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
-
- "lucide-react": ["lucide-react@0.460.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, "sha512-BVtq/DykVeIvRTJvRAgCsOwaGL8Un3Bxh8MbDxMhEWlZay3T4IpEKDEpwt5KZ0KJMHzgm6jrltxlT5eXOWXDHg=="],
-
- "luxon": ["luxon@3.5.0", "", {}, "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ=="],
+ "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="],
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
- "motion-dom": ["motion-dom@12.23.23", "", { "dependencies": { "motion-utils": "^12.23.6" } }, "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA=="],
+ "motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="],
- "motion-utils": ["motion-utils@12.23.6", "", {}, "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ=="],
+ "motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
- "nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="],
-
- "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
+ "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
- "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
+ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
- "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
+ "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="],
- "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
+ "react": ["react@19.2.6", "", {}, "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q=="],
- "react": ["react@19.0.0", "", {}, "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="],
+ "react-dom": ["react-dom@19.2.6", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.6" } }, "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g=="],
- "react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="],
-
- "react-i18next": ["react-i18next@15.4.1", "", { "dependencies": { "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 23.2.3", "react": ">= 16.8.0" } }, "sha512-ahGab+IaSgZmNPYXdV1n+OYky95TGpFwnKRflX/16dY04DsYYKHtVLjeny7sBSCREEcoMbAgSkFiGLF5g5Oofw=="],
+ "react-i18next": ["react-i18next@17.0.8", "", { "dependencies": { "@babel/runtime": "^7.29.2", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "i18next": ">= 26.2.0", "react": ">= 16.8.0", "react-dom": "*", "react-native": "*", "typescript": "^5 || ^6" }, "optionalPeers": ["react-dom", "react-native", "typescript"] }, "sha512-0ooKbGLU8JXhe1zwpQUWIeXSgLPOfwJmgheWRIUpcoA0CpyabpGhayjdG+/eA5esC1AQ8h2jWpXjJfzQzeDOCw=="],
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
+ "react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="],
+
"react-remove-scroll": ["react-remove-scroll@2.6.3", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ=="],
"react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
- "react-router": ["react-router@7.13.0", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw=="],
+ "react-router": ["react-router@7.15.1", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A=="],
- "react-router-dom": ["react-router-dom@7.13.0", "", { "dependencies": { "react-router": "7.13.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g=="],
-
- "react-smooth": ["react-smooth@4.0.4", "", { "dependencies": { "fast-equals": "^5.0.1", "prop-types": "^15.8.1", "react-transition-group": "^4.4.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q=="],
+ "react-router-dom": ["react-router-dom@7.15.1", "", { "dependencies": { "react-router": "7.15.1" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg=="],
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
- "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="],
+ "recharts": ["recharts@3.8.1", "", { "dependencies": { "@reduxjs/toolkit": "^1.9.0 || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg=="],
- "recharts": ["recharts@2.15.1", "", { "dependencies": { "clsx": "^2.0.0", "eventemitter3": "^4.0.1", "lodash": "^4.17.21", "react-is": "^18.3.1", "react-smooth": "^4.0.4", "recharts-scale": "^0.4.4", "tiny-invariant": "^1.3.1", "victory-vendor": "^36.6.8" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-v8PUTUlyiDe56qUj82w/EDVuzEFXwEHp9/xOowGAZwfLjB9uAy3GllQVIYMWF6nU+qibx85WF75zD7AjqoT54Q=="],
+ "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
- "recharts-scale": ["recharts-scale@0.4.5", "", { "dependencies": { "decimal.js-light": "^2.4.1" } }, "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w=="],
+ "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
- "regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="],
+ "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
- "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="],
+ "rolldown": ["rolldown@1.0.2", "", { "dependencies": { "@oxc-project/types": "=0.132.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.2", "@rolldown/binding-darwin-arm64": "1.0.2", "@rolldown/binding-darwin-x64": "1.0.2", "@rolldown/binding-freebsd-x64": "1.0.2", "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", "@rolldown/binding-linux-arm64-gnu": "1.0.2", "@rolldown/binding-linux-arm64-musl": "1.0.2", "@rolldown/binding-linux-ppc64-gnu": "1.0.2", "@rolldown/binding-linux-s390x-gnu": "1.0.2", "@rolldown/binding-linux-x64-gnu": "1.0.2", "@rolldown/binding-linux-x64-musl": "1.0.2", "@rolldown/binding-openharmony-arm64": "1.0.2", "@rolldown/binding-wasm32-wasi": "1.0.2", "@rolldown/binding-win32-arm64-msvc": "1.0.2", "@rolldown/binding-win32-x64-msvc": "1.0.2" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g=="],
- "scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="],
+ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
- "sonner": ["sonner@1.7.4", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw=="],
+ "sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
- "tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="],
+ "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="],
- "tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
+ "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="],
"tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="],
- "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
+ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
- "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
+ "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
"tslib": ["tslib@2.8.0", "", {}, "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="],
- "typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="],
+ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
- "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
+ "undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
"use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
- "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="],
+ "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
- "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
+ "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
+
+ "vite": ["vite@8.0.14", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.2", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw=="],
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
+ "@emnapi/wasi-threads/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
"@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
"@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
- "@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="],
-
- "@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
+ "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
"@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
+ "@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
+ "@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
+ "@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
+ "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
+ "@radix-ui/react-progress/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
+ "@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
+ "@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
+ "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="],
- "@radix-ui/react-menu/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
+ "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
- "@radix-ui/react-menu/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg=="],
+ "@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="],
- "@radix-ui/react-menu/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="],
- "@radix-ui/react-menu/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
- "@radix-ui/react-popover/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
- "@radix-ui/react-popover/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg=="],
-
- "@radix-ui/react-popover/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA=="],
-
- "@radix-ui/react-popover/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
-
- "@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="],
-
- "@radix-ui/react-portal/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-select/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
-
- "@radix-ui/react-select/@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg=="],
-
- "@radix-ui/react-select/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA=="],
-
- "@radix-ui/react-select/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
-
- "@radix-ui/react-tooltip/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
-
- "@radix-ui/react-tooltip/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
-
- "@radix-ui/react-use-effect-event/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
-
- "@radix-ui/react-use-escape-keydown/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
-
- "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.0", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" }, "bundled": true }, "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA=="],
+ "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="],
"@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
- "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.0", "", { "bundled": true }, "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="],
+ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "cmdk/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"cmdk/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw=="],
- "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
+ "cmdk/@radix-ui/react-id": ["@radix-ui/react-id@1.1.0", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA=="],
- "@radix-ui/react-dialog/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
+ "cmdk/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
- "@radix-ui/react-dialog/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/core/tslib": ["tslib@2.8.0", "", {}, "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="],
- "@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
+ "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime/tslib": ["tslib@2.8.0", "", {}, "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="],
- "@radix-ui/react-dismissable-layer/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
+ "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util/tslib": ["tslib@2.8.0", "", {}, "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="],
- "@radix-ui/react-focus-scope/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
+ "cmdk/@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
- "@radix-ui/react-menu/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
-
- "@radix-ui/react-popover/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
-
- "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
-
- "@radix-ui/react-select/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
-
- "@radix-ui/react-tooltip/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"cmdk/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
@@ -702,8 +568,26 @@
"cmdk/@radix-ui/react-dialog/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
- "@radix-ui/react-portal/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
+
+ "cmdk/@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
+
+ "cmdk/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"cmdk/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer/@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-portal/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
+
+ "cmdk/@radix-ui/react-dialog/@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
}
}
diff --git a/index.html b/index.html
index 34e9f65..4039a54 100644
--- a/index.html
+++ b/index.html
@@ -1,5 +1,5 @@
-
+
-
"),
+ );
+
+ renderApp();
+
+ await waitFor(() => {
+ expect(appMocks.injectContext).toHaveBeenCalledWith(
+ "",
+ );
+ });
+ expect(await screen.findByText("server-page")).toBeInTheDocument();
+ });
+
+ it("renders fetch errors through the error page", async () => {
+ appMocks.fetchSetting.mockRejectedValue(new Error("settings failed"));
+
+ renderApp();
+
+ expect(await screen.findByText("settings failed")).toBeInTheDocument();
+ });
+
+ it("routes server detail paths through the app router", async () => {
+ renderApp("/server/42");
+
+ expect(await screen.findByText("server-detail-page")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/RemainPercentBar.test.tsx b/src/test/components/RemainPercentBar.test.tsx
new file mode 100644
index 0000000..3c04610
--- /dev/null
+++ b/src/test/components/RemainPercentBar.test.tsx
@@ -0,0 +1,22 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+
+import RemainPercentBar from "@/components/RemainPercentBar";
+
+describe("RemainPercentBar", () => {
+ it("uses status colors for low, medium, and healthy remaining percentages", () => {
+ const { rerender } = render();
+ const progress = screen.getByRole("progressbar");
+ const indicator = progress.firstElementChild;
+
+ expect(progress).toHaveClass("w-[70px]");
+ expect(indicator).toHaveClass("bg-red-500");
+ expect(indicator).toHaveStyle({ transform: "translateX(-71%)" });
+
+ rerender();
+ expect(progress.firstElementChild).toHaveClass("bg-orange-400");
+
+ rerender();
+ expect(progress.firstElementChild).toHaveClass("bg-green-500");
+ });
+});
diff --git a/src/test/components/ThemeProvider.test.tsx b/src/test/components/ThemeProvider.test.tsx
new file mode 100644
index 0000000..3fbb659
--- /dev/null
+++ b/src/test/components/ThemeProvider.test.tsx
@@ -0,0 +1,144 @@
+import { act, render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { ThemeColorManager } from "@/components/ThemeColorManager";
+import {
+ ThemeProvider,
+ ThemeProviderContext,
+} from "@/components/ThemeProvider";
+import { useTheme } from "@/hooks/use-theme";
+
+function ThemeProbe() {
+ const { setTheme, theme } = useTheme();
+
+ return (
+
+
{theme}
+
+
+
+ );
+}
+
+function InvalidThemeProbe() {
+ useTheme();
+ return null;
+}
+
+describe("ThemeProvider", () => {
+ it("applies theme classes, meta color, and localStorage state", async () => {
+ const user = userEvent.setup();
+ const meta = document.createElement("meta");
+ meta.name = "theme-color";
+ document.head.appendChild(meta);
+
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByTestId("theme-state")).toHaveTextContent("system");
+ expect(document.documentElement).toHaveClass("light");
+
+ await user.click(screen.getByRole("button", { name: "dark" }));
+
+ expect(screen.getByTestId("theme-state")).toHaveTextContent("dark");
+ expect(localStorage.getItem("theme-test")).toBe("dark");
+ expect(document.documentElement).toHaveClass("dark");
+ expect(document.documentElement.style.colorScheme).toBe("dark");
+ expect(document.querySelector('meta[name="theme-color"]')).toHaveAttribute(
+ "content",
+ "hsl(30 15% 8%)",
+ );
+
+ await user.click(screen.getByRole("button", { name: "light" }));
+ expect(document.documentElement).toHaveClass("light");
+ });
+
+ it("uses stored theme value as the initial theme", () => {
+ localStorage.setItem("theme-test", "dark");
+
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByTestId("theme-state")).toHaveTextContent("dark");
+ expect(document.documentElement).toHaveClass("dark");
+ });
+
+ it("follows system color scheme changes and cleans up its listener", () => {
+ let systemDark = true;
+ let changeListener: (() => void) | undefined;
+ const addEventListener = vi.fn((_event: string, listener: () => void) => {
+ changeListener = listener;
+ });
+ const removeEventListener = vi.fn();
+
+ vi.mocked(window.matchMedia).mockReturnValue({
+ get matches() {
+ return systemDark;
+ },
+ media: "(prefers-color-scheme: dark)",
+ onchange: null,
+ addListener: vi.fn(),
+ removeListener: vi.fn(),
+ addEventListener,
+ removeEventListener,
+ dispatchEvent: vi.fn(),
+ } as unknown as MediaQueryList);
+
+ const { unmount } = render(
+
+
+ ,
+ );
+
+ expect(document.documentElement).toHaveClass("dark");
+
+ act(() => {
+ systemDark = false;
+ changeListener?.();
+ });
+
+ expect(document.documentElement).toHaveClass("light");
+
+ unmount();
+
+ expect(removeEventListener).toHaveBeenCalledWith("change", changeListener);
+ });
+
+ it("keeps theme-color meta in sync through ThemeColorManager", () => {
+ render(
+
+
+
+ ,
+ );
+
+ act(() => {
+ screen.getByRole("button", { name: "dark" }).click();
+ });
+
+ expect(document.querySelector('meta[name="theme-color"]')).toHaveAttribute(
+ "content",
+ "hsl(30 15% 8%)",
+ );
+ });
+
+ it("throws when the theme context is explicitly unavailable", () => {
+ expect(() =>
+ render(
+
+
+ ,
+ ),
+ ).toThrow("useTheme must be used within a ThemeProvider");
+ });
+});
diff --git a/src/test/components/basic-components.test.tsx b/src/test/components/basic-components.test.tsx
new file mode 100644
index 0000000..6d16986
--- /dev/null
+++ b/src/test/components/basic-components.test.tsx
@@ -0,0 +1,190 @@
+import { fireEvent, render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import AnimateCountClient, { AnimateCount } from "@/components/AnimatedCount";
+import ErrorBoundary from "@/components/ErrorBoundary";
+import ChartSkeleton from "@/components/loading/ChartSkeleton";
+import { Loader, LoadingSpinner } from "@/components/loading/Loader";
+import NetworkChartLoading from "@/components/NetworkChartLoading";
+import { SearchButton } from "@/components/SearchButton";
+import ServerOverview from "@/components/ServerOverview";
+import ServerUsageBar from "@/components/ServerUsageBar";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Separator } from "@/components/ui/separator";
+import { Skeleton } from "@/components/ui/skeleton";
+
+vi.mock("@numeric-text/react", () => ({
+ default: ({
+ className,
+ value,
+ }: {
+ className?: string;
+ value: string | number;
+ }) => {value},
+}));
+
+import { CommandProvider } from "@/context/command-provider";
+import { StatusProvider } from "@/context/status-provider";
+import { useCommand } from "@/hooks/use-command";
+import { useStatus } from "@/hooks/use-status";
+
+function BrokenComponent(): never {
+ throw new Error("render failed");
+}
+
+function CommandReadout() {
+ const { isOpen } = useCommand();
+ return {isOpen ? "command-open" : "command-closed"}
;
+}
+
+function StatusReadout() {
+ const { status } = useStatus();
+ return {`status:${status}`}
;
+}
+
+describe("basic display components", () => {
+ it("renders animated counts with padded digits", () => {
+ render({7});
+
+ expect(screen.getAllByText("0")).toHaveLength(4);
+ expect(screen.getAllByText("7")).toHaveLength(1);
+ });
+
+ it("keeps the animated count client stable across count changes", () => {
+ const { rerender } = render(
+ ,
+ );
+
+ expect(screen.getAllByText("1")).toHaveLength(2);
+ rerender();
+ expect(screen.getByText("2")).toBeInTheDocument();
+ });
+
+ it("renders server usage colors for healthy, warning, and critical values", () => {
+ const { rerender } = render();
+ expect(screen.getByRole("progressbar").firstElementChild).toHaveClass(
+ "bg-green-500",
+ );
+
+ rerender();
+ expect(screen.getByRole("progressbar").firstElementChild).toHaveClass(
+ "bg-orange-400",
+ );
+
+ rerender();
+ expect(screen.getByRole("progressbar").firstElementChild).toHaveClass(
+ "bg-red-500",
+ );
+ });
+
+ it("renders loading primitives", () => {
+ const { container } = render(
+ <>
+
+
+
+
+ >,
+ );
+
+ expect(
+ container.querySelector("[data-visible='true']"),
+ ).toBeInTheDocument();
+ expect(container.querySelectorAll(".hamster-loading-bar")).toHaveLength(16);
+ expect(container.querySelector(".animate-spin")).toBeInTheDocument();
+ expect(container.querySelector(".h-\\[250px\\]")).toBeInTheDocument();
+ });
+
+ it("catches render errors with ErrorBoundary", () => {
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("500")).toBeInTheDocument();
+ expect(screen.getByText("render failed")).toBeInTheDocument();
+ });
+});
+
+describe("interactive app controls", () => {
+ it("opens command search from the search button", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+
+ ,
+ );
+
+ expect(screen.getByText("command-closed")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "Search" }));
+ expect(screen.getByText("command-open")).toBeInTheDocument();
+ });
+
+ it("lets overview cards update the global status filter", () => {
+ render(
+
+
+
+ ,
+ );
+
+ expect(screen.getByText("status:all")).toBeInTheDocument();
+ fireEvent.click(screen.getByText("serverOverview.onlineServers"));
+ expect(screen.getByText("status:online")).toBeInTheDocument();
+ fireEvent.click(screen.getByText("serverOverview.offlineServers"));
+ expect(screen.getByText("status:offline")).toBeInTheDocument();
+ fireEvent.click(screen.getByText("serverOverview.totalServers"));
+ expect(screen.getByText("status:all")).toBeInTheDocument();
+ });
+});
+
+describe("ui primitives", () => {
+ it("forwards classes and events through Button and Input", async () => {
+ const user = userEvent.setup();
+ const onClick = vi.fn();
+ const onChange = vi.fn();
+ render(
+ <>
+
+
+ >,
+ );
+
+ await user.click(screen.getByRole("button", { name: "Save" }));
+ await user.type(screen.getByPlaceholderText("Name"), "edge");
+
+ expect(onClick).toHaveBeenCalledOnce();
+ expect(onChange).toHaveBeenCalled();
+ expect(screen.getByRole("button", { name: "Save" })).toHaveClass(
+ "bg-secondary",
+ );
+ });
+
+ it("renders skeletons and separators with expected orientation classes", () => {
+ const { container } = render(
+ <>
+
+
+
+ >,
+ );
+
+ expect(screen.getByTestId("skeleton")).toHaveClass("animate-pulse", "h-4");
+ expect(screen.getByTestId("horizontal")).toHaveClass("h-px", "w-full");
+ expect(screen.getByTestId("vertical")).toHaveClass("h-full", "w-px");
+ expect(container.querySelectorAll("[data-orientation]")).toHaveLength(2);
+ });
+});
diff --git a/src/test/components/chart-primitives.test.tsx b/src/test/components/chart-primitives.test.tsx
new file mode 100644
index 0000000..f7c85db
--- /dev/null
+++ b/src/test/components/chart-primitives.test.tsx
@@ -0,0 +1,136 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import {
+ ChartContainer,
+ ChartLegendContent,
+ ChartTooltipContent,
+} from "@/components/ui/chart";
+
+function CpuIcon() {
+ return icon;
+}
+
+const chartConfig = {
+ cpu: {
+ label: "CPU Usage",
+ icon: CpuIcon,
+ },
+ mem: {
+ label: "Memory",
+ color: "#00ff00",
+ },
+ themed: {
+ label: "Themed",
+ theme: {
+ light: "#ffffff",
+ dark: "#000000",
+ },
+ },
+};
+
+describe("chart primitives", () => {
+ it("renders tooltip rows with config labels, icons, and formatted values", () => {
+ const formatter = vi.fn((value: number, name: string) => (
+ {`${name}:${value.toFixed(1)}`}
+ ));
+
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("CPU Usage")).toBeInTheDocument();
+ expect(screen.getByText("cpu:12.3")).toBeInTheDocument();
+ expect(screen.getByText("mem:42.0")).toBeInTheDocument();
+ expect(formatter).toHaveBeenCalled();
+ });
+
+ it("renders nested labels for single line indicators and hides inactive tooltips", () => {
+ const { container, rerender } = render(
+
+
+ ,
+ );
+
+ expect(screen.getAllByText("CPU Usage")).toHaveLength(2);
+ expect(screen.getByText("12.00")).toBeInTheDocument();
+
+ rerender(
+
+
+ ,
+ );
+
+ expect(container).not.toHaveTextContent("CPU Usage");
+ });
+
+ it("renders legend payloads and chart theme style blocks", () => {
+ const { container, rerender } = render(
+
+
+ ,
+ );
+
+ expect(screen.getByTestId("cpu-icon")).toBeInTheDocument();
+ expect(screen.getByText("mem")).toBeInTheDocument();
+ expect(container.querySelector("style")?.textContent).toContain(
+ "--color-themed",
+ );
+
+ rerender(
+
+
+ ,
+ );
+
+ expect(screen.queryByText("mem")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/dash-command.test.tsx b/src/test/components/dash-command.test.tsx
new file mode 100644
index 0000000..14d89e7
--- /dev/null
+++ b/src/test/components/dash-command.test.tsx
@@ -0,0 +1,92 @@
+import { fireEvent, render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { DashCommand } from "@/components/DashCommand";
+import { createServer } from "@/test/fixtures";
+
+const dashMocks = vi.hoisted(() => ({
+ closeCommand: vi.fn(),
+ isOpen: true,
+ lastMessage: null as MessageEvent | null,
+ navigate: vi.fn(),
+ setTheme: vi.fn(),
+ toggleCommand: vi.fn(),
+ connected: true,
+}));
+
+vi.mock("@/hooks/use-command", () => ({
+ useCommand: () => ({
+ closeCommand: dashMocks.closeCommand,
+ isOpen: dashMocks.isOpen,
+ toggleCommand: dashMocks.toggleCommand,
+ }),
+}));
+
+vi.mock("@/hooks/use-theme", () => ({
+ useTheme: () => ({
+ setTheme: dashMocks.setTheme,
+ }),
+}));
+
+vi.mock("@/hooks/use-websocket-context", () => ({
+ useWebSocketContext: () => ({
+ connected: dashMocks.connected,
+ lastMessage: dashMocks.lastMessage,
+ }),
+}));
+
+vi.mock("react-router-dom", async (importOriginal) => {
+ const actual = await importOriginal();
+ return {
+ ...actual,
+ useNavigate: () => dashMocks.navigate,
+ };
+});
+
+function seedWebSocketData() {
+ dashMocks.connected = true;
+ dashMocks.lastMessage = new MessageEvent("message", {
+ data: JSON.stringify({
+ now: Date.parse("2025-01-01T00:00:00.000Z") / 1000,
+ servers: [
+ createServer({
+ id: 7,
+ name: "edge-7",
+ last_active: "2025-01-01T00:00:00.000Z",
+ }),
+ ],
+ }),
+ });
+}
+
+describe("DashCommand", () => {
+ it("does not render until websocket data is available", () => {
+ dashMocks.connected = false;
+ dashMocks.lastMessage = null;
+
+ const { container } = render();
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
+ it("renders server and shortcut commands, handles selection, and listens for keyboard toggle", async () => {
+ const user = userEvent.setup();
+ seedWebSocketData();
+
+ render();
+
+ fireEvent.keyDown(document, { key: "k", metaKey: true });
+ expect(dashMocks.toggleCommand).toHaveBeenCalledOnce();
+
+ expect(screen.getByPlaceholderText("TypeCommand")).toBeInTheDocument();
+ expect(screen.getByText("edge-7")).toBeInTheDocument();
+ expect(screen.getByText("ToggleDarkMode")).toBeInTheDocument();
+
+ await user.click(screen.getByText("edge-7"));
+ expect(dashMocks.navigate).toHaveBeenCalledWith("/server/7");
+ expect(dashMocks.closeCommand).toHaveBeenCalled();
+
+ await user.click(screen.getByText("ToggleDarkMode"));
+ expect(dashMocks.setTheme).toHaveBeenCalledWith("dark");
+ });
+});
diff --git a/src/test/components/global-map.test.tsx b/src/test/components/global-map.test.tsx
new file mode 100644
index 0000000..a5b8fdd
--- /dev/null
+++ b/src/test/components/global-map.test.tsx
@@ -0,0 +1,175 @@
+import { fireEvent, render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter, useLocation } from "react-router-dom";
+import { describe, expect, it } from "vitest";
+import GlobalMap, { InteractiveMap } from "@/components/GlobalMap";
+import { TooltipProvider } from "@/context/tooltip-provider";
+import { createServer } from "@/test/fixtures";
+
+type InteractiveMapProps = Parameters[0];
+
+const now = Date.parse("2025-01-01T00:00:20.000Z");
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+function renderMap(ui: React.ReactElement) {
+ return render(
+
+
+ {ui}
+
+
+ ,
+ );
+}
+
+function mapFeature(code: string, name: string) {
+ return {
+ type: "Feature",
+ properties: {
+ iso_a2_eh: code,
+ iso_a3_eh: `${code}A`,
+ name,
+ },
+ geometry: {
+ type: "Polygon",
+ coordinates: [
+ [
+ [-100, 30],
+ [-90, 30],
+ [-90, 40],
+ [-100, 40],
+ [-100, 30],
+ ],
+ ],
+ },
+ };
+}
+
+describe("GlobalMap", () => {
+ it("counts unique countries and ignores servers without country codes", () => {
+ Object.assign(window, { CustomBackgroundImage: "/background.png" });
+
+ const { container } = renderMap(
+ ,
+ );
+
+ expect(
+ screen.getByText(/map\.Distributions 2 map\.Regions/),
+ ).toBeInTheDocument();
+ expect(container.querySelector("section")).toHaveClass("bg-card/70");
+ });
+});
+
+describe("InteractiveMap", () => {
+ it("shows country tooltips, navigates from servers, and clears tooltip state", async () => {
+ const user = userEvent.setup();
+ const filteredFeatures = [
+ mapFeature("US", "United States"),
+ mapFeature("DE", "Germany"),
+ ] as unknown as InteractiveMapProps["filteredFeatures"];
+
+ const { container } = renderMap(
+ ,
+ );
+
+ const highlightedCountry = container.querySelector("path.fill-green-700");
+ expect(highlightedCountry).toBeInTheDocument();
+
+ fireEvent.mouseEnter(highlightedCountry as SVGPathElement);
+
+ expect(await screen.findByText("United States")).toBeInTheDocument();
+ expect(screen.getByText("2 map.Servers")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: /us-offline/ }));
+
+ expect(sessionStorage.getItem("fromMainPage")).toBe("true");
+ expect(screen.getByText("/server/12")).toBeInTheDocument();
+
+ const fallbackMarker = container.querySelector("circle.fill-sky-700");
+ expect(fallbackMarker).toBeInTheDocument();
+
+ fireEvent.mouseEnter(fallbackMarker as SVGCircleElement);
+
+ expect(await screen.findByText("Singapore")).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: /sg-edge/ })).toBeInTheDocument();
+
+ fireEvent.mouseLeave(container.querySelector(".relative") as HTMLElement);
+
+ expect(screen.queryByText("Singapore")).not.toBeInTheDocument();
+ });
+
+ it("clears tooltip state for non-highlighted countries and empty map areas", () => {
+ const filteredFeatures = [
+ mapFeature("US", "United States"),
+ mapFeature("DE", "Germany"),
+ ] as unknown as InteractiveMapProps["filteredFeatures"];
+
+ const { container } = renderMap(
+ ,
+ );
+
+ const [highlightedCountry, neutralCountry] = Array.from(
+ container.querySelectorAll("path"),
+ );
+ fireEvent.mouseEnter(highlightedCountry as SVGPathElement);
+ expect(screen.getByText("United States")).toBeInTheDocument();
+
+ fireEvent.mouseEnter(neutralCountry as SVGPathElement);
+ expect(screen.queryByText("United States")).not.toBeInTheDocument();
+
+ fireEvent.mouseEnter(container.querySelector("rect") as SVGRectElement);
+ expect(screen.queryByText("United States")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/header.test.tsx b/src/test/components/header.test.tsx
new file mode 100644
index 0000000..435c45e
--- /dev/null
+++ b/src/test/components/header.test.tsx
@@ -0,0 +1,243 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import type { ReactElement } from "react";
+import { MemoryRouter, useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import Header, { RefreshToast } from "@/components/Header";
+import { ThemeProvider } from "@/components/ThemeProvider";
+import { CommandProvider } from "@/context/command-provider";
+import { createSettingResponse } from "@/test/fixtures";
+import { createTestQueryClient } from "@/test/utils";
+
+const headerMocks = vi.hoisted(() => ({
+ backgroundImage: undefined as string | undefined,
+ connected: true,
+ fetchLoginUser: vi.fn(),
+ fetchSetting: vi.fn(),
+ lastMessage: null as MessageEvent | null,
+ needReconnect: false,
+ setNeedReconnect: vi.fn(),
+ updateBackground: vi.fn(),
+}));
+
+vi.mock("@numeric-text/react", () => ({
+ default: ({ value }: { value: string | number }) => (
+ {value}
+ ),
+}));
+
+vi.mock("@/hooks/use-background", () => ({
+ useBackground: () => ({
+ backgroundImage: headerMocks.backgroundImage,
+ updateBackground: headerMocks.updateBackground,
+ }),
+}));
+
+vi.mock("@/hooks/use-websocket-context", () => ({
+ useWebSocketContext: () => ({
+ connected: headerMocks.connected,
+ lastMessage: headerMocks.lastMessage,
+ needReconnect: headerMocks.needReconnect,
+ setNeedReconnect: headerMocks.setNeedReconnect,
+ }),
+}));
+
+vi.mock("@/lib/nezha-api", () => ({
+ fetchLoginUser: headerMocks.fetchLoginUser,
+ fetchSetting: headerMocks.fetchSetting,
+}));
+
+function settingResponse(siteName = "Nezha") {
+ return {
+ ...createSettingResponse(),
+ data: {
+ ...createSettingResponse().data,
+ config: {
+ ...createSettingResponse().data.config,
+ site_name: siteName,
+ },
+ },
+ };
+}
+
+function loginResponse() {
+ return {
+ success: true,
+ data: {
+ id: 1,
+ username: "admin",
+ password: "",
+ created_at: "2025-01-01T00:00:00.000Z",
+ updated_at: "2025-01-01T00:00:00.000Z",
+ },
+ };
+}
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+function renderHeader(route = "/server/1") {
+ return render(
+
+
+
+
+
+
+
+
+
+ ,
+ );
+}
+
+function renderInRouter(ui: ReactElement) {
+ return render({ui});
+}
+
+describe("Header", () => {
+ beforeEach(() => {
+ headerMocks.backgroundImage = undefined;
+ headerMocks.connected = true;
+ headerMocks.fetchLoginUser.mockReset();
+ headerMocks.fetchSetting.mockReset();
+ headerMocks.lastMessage = new MessageEvent("message", {
+ data: JSON.stringify({ online: 4 }),
+ });
+ headerMocks.needReconnect = false;
+ headerMocks.setNeedReconnect.mockReset();
+ headerMocks.updateBackground.mockReset();
+ Object.assign(window, {
+ CustomBackgroundImage: "",
+ CustomDesc: "",
+ CustomLinks: "",
+ CustomLogo: "",
+ CustomMobileBackgroundImage: "",
+ });
+ headerMocks.fetchSetting.mockResolvedValue(settingResponse());
+ headerMocks.fetchLoginUser.mockRejectedValue(new Error("anonymous"));
+ });
+
+ it("renders configured site identity, custom links, online count, and dashboard state", async () => {
+ const user = userEvent.setup();
+ Object.assign(window, {
+ CustomDesc: "edge status",
+ CustomLinks: JSON.stringify([
+ { link: "https://example.test", name: "Docs" },
+ ]),
+ CustomLogo: "/logo.png",
+ });
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "session=1",
+ });
+ sessionStorage.setItem("selectedGroup", "Edge");
+ headerMocks.fetchSetting.mockResolvedValue(settingResponse("Status Hub"));
+ headerMocks.fetchLoginUser.mockResolvedValue(loginResponse());
+
+ renderHeader();
+
+ const siteName = await screen.findByText("Status Hub");
+ expect(screen.getByText("edge status")).toBeInTheDocument();
+ expect(screen.getByAltText("apple-touch-icon")).toHaveAttribute(
+ "src",
+ "/logo.png",
+ );
+ expect(screen.getAllByRole("link", { name: "Docs" })).toHaveLength(2);
+ expect(await screen.findAllByText("dashboard")).toHaveLength(2);
+ expect(screen.getByTestId("numeric-text")).toHaveTextContent("4");
+ expect(screen.getByText("online")).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(document.title).toBe("Status Hub");
+ });
+ expect(document.querySelector("link[rel='shortcut icon']")).toHaveAttribute(
+ "href",
+ "/logo.png",
+ );
+
+ await user.click(siteName);
+
+ expect(sessionStorage.getItem("selectedGroup")).toBeNull();
+ expect(screen.getByText("/")).toBeInTheDocument();
+ });
+
+ it("uses the offline display and login links when websocket and auth are unavailable", async () => {
+ headerMocks.connected = false;
+
+ const { container } = renderHeader();
+
+ expect(await screen.findAllByText("login")).toHaveLength(2);
+ expect(screen.getByText("offline")).toBeInTheDocument();
+ expect(
+ container.querySelector("[data-visible='true']"),
+ ).toBeInTheDocument();
+ });
+
+ it("stores and removes the active custom background", async () => {
+ const user = userEvent.setup();
+ headerMocks.backgroundImage = "/desktop.png";
+ Object.assign(window, {
+ CustomBackgroundImage: "/desktop.png",
+ CustomMobileBackgroundImage: "/mobile.png",
+ });
+
+ const { container } = renderHeader();
+ await screen.findByText("Nezha");
+
+ const toggleButton = container
+ .querySelector(".lucide-image-minus")
+ ?.closest("button");
+ expect(toggleButton).toBeInTheDocument();
+
+ await user.click(toggleButton as HTMLButtonElement);
+
+ expect(sessionStorage.getItem("savedBackgroundImage")).toBe("/desktop.png");
+ expect(headerMocks.updateBackground).toHaveBeenCalledWith(undefined);
+ });
+
+ it("restores the saved custom background", async () => {
+ const user = userEvent.setup();
+ sessionStorage.setItem("savedBackgroundImage", "/saved.png");
+
+ const { container } = renderHeader();
+ await screen.findByText("Nezha");
+
+ const toggleButton = container
+ .querySelector(".lucide-image-minus")
+ ?.closest("button");
+ expect(toggleButton).toBeInTheDocument();
+
+ await user.click(toggleButton as HTMLButtonElement);
+
+ expect(headerMocks.updateBackground).toHaveBeenCalledWith("/saved.png");
+ });
+});
+
+describe("RefreshToast", () => {
+ beforeEach(() => {
+ headerMocks.needReconnect = false;
+ });
+
+ it("renders only while reconnect refresh is needed", () => {
+ vi.useFakeTimers();
+ sessionStorage.setItem("needRefresh", "true");
+
+ const { container, rerender } = renderInRouter();
+
+ expect(container).toBeEmptyDOMElement();
+
+ headerMocks.needReconnect = true;
+ rerender(
+
+
+ ,
+ );
+
+ expect(screen.getByText("refreshing...")).toBeInTheDocument();
+ expect(sessionStorage.getItem("needRefresh")).toBeNull();
+ });
+});
diff --git a/src/test/components/info-components.test.tsx b/src/test/components/info-components.test.tsx
new file mode 100644
index 0000000..11036c6
--- /dev/null
+++ b/src/test/components/info-components.test.tsx
@@ -0,0 +1,218 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { useEffect } from "react";
+import { MemoryRouter, useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import BillingInfo from "@/components/billingInfo";
+import MapTooltip from "@/components/MapTooltip";
+import PlanInfo from "@/components/PlanInfo";
+import ServerFlag from "@/components/ServerFlag";
+import { TooltipProvider } from "@/context/tooltip-provider";
+import { useTooltip } from "@/hooks/use-tooltip";
+import type { PublicNoteData } from "@/lib/utils";
+
+const planData: PublicNoteData = {
+ planDataMod: {
+ bandwidth: "1Gbps",
+ trafficVol: "2TB",
+ trafficType: "monthly",
+ IPv4: "1",
+ IPv6: "1",
+ networkRoute: "CN2,CMI",
+ extra: "Premium,Backup",
+ },
+};
+
+function TooltipSeeder() {
+ const { setTooltipData } = useTooltip();
+
+ useEffect(() => {
+ setTooltipData({
+ centroid: [12, 34],
+ country: "China",
+ count: 2,
+ servers: [
+ { id: 1, name: "edge-1", status: true },
+ { id: 2, name: "edge-2", status: false },
+ ],
+ });
+ }, [setTooltipData]);
+
+ return null;
+}
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+describe("PlanInfo and BillingInfo", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.setSystemTime(new Date("2025-01-15T00:00:00.000Z"));
+ });
+
+ it("renders plan badges for every supported public note field", () => {
+ render();
+
+ expect(screen.getByText("1Gbps")).toBeInTheDocument();
+ expect(screen.getByText("2TB")).toBeInTheDocument();
+ expect(screen.getByText("IPv4")).toBeInTheDocument();
+ expect(screen.getByText("IPv6")).toBeInTheDocument();
+ expect(screen.getByText("CN2|CMI")).toBeInTheDocument();
+ expect(screen.getByText("Premium")).toBeInTheDocument();
+ expect(screen.getByText("Backup")).toBeInTheDocument();
+ });
+
+ it("renders active, free, usage-based, indefinite, and expired billing states", () => {
+ const { rerender } = render(
+ ,
+ );
+
+ expect(
+ screen.getByText("billingInfo.price: 10/monthly"),
+ ).toBeInTheDocument();
+ expect(screen.getByText(/billingInfo.remaining: 16/)).toBeInTheDocument();
+ expect(screen.getByRole("progressbar")).toBeInTheDocument();
+
+ rerender(
+ ,
+ );
+ expect(screen.getByText("billingInfo.free")).toBeInTheDocument();
+
+ rerender(
+ ,
+ );
+ expect(screen.getByText("billingInfo.usage-baseed")).toBeInTheDocument();
+
+ rerender(
+ ,
+ );
+ expect(screen.getByText(/billingInfo.indefinite/)).toBeInTheDocument();
+
+ rerender(
+ ,
+ );
+ expect(screen.getByText(/billingInfo.expired/)).toBeInTheDocument();
+ });
+});
+
+describe("MapTooltip", () => {
+ it("renders tooltip data and navigates to selected servers", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+
+
+
+
+ ,
+ );
+
+ expect(await screen.findByText("Mainland China")).toBeInTheDocument();
+ expect(screen.getByText("2 map.Servers")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: /edge-2/ }));
+
+ expect(sessionStorage.getItem("fromMainPage")).toBe("true");
+ expect(screen.getByText("/server/2")).toBeInTheDocument();
+ });
+});
+
+describe("ServerFlag", () => {
+ it("uses SVG flag classes when emoji flags are forced off", () => {
+ Object.assign(window, { ForceUseSvgFlag: true });
+ const { container } = render();
+
+ expect(container.querySelector(".fi-us")).toBeInTheDocument();
+ });
+
+ it("uses emoji flags when the canvas probe detects support", async () => {
+ Object.assign(window, { ForceUseSvgFlag: false });
+ const originalCreateElement = document.createElement.bind(document);
+ const canvasContext = {
+ fillStyle: "",
+ textBaseline: "",
+ font: "",
+ fillText: vi.fn(),
+ getImageData: vi.fn(() => ({
+ data: new Uint8ClampedArray([0, 0, 0, 255]),
+ })),
+ } as unknown as CanvasRenderingContext2D;
+ vi.spyOn(document, "createElement").mockImplementation(
+ (tagName, options) => {
+ if (tagName === "canvas") {
+ return {
+ getContext: vi.fn(() => canvasContext),
+ } as unknown as HTMLCanvasElement;
+ }
+
+ return originalCreateElement(tagName, options);
+ },
+ );
+
+ const { container } = render();
+
+ await waitFor(() => {
+ expect(container).toHaveTextContent("🇺🇸");
+ });
+ expect(container.querySelector(".fi-US")).not.toBeInTheDocument();
+ });
+
+ it("renders nothing for missing country codes", () => {
+ Object.assign(window, { ForceUseSvgFlag: true });
+ const { container } = render();
+
+ expect(container).toBeEmptyDOMElement();
+ });
+});
diff --git a/src/test/components/navigation-and-footer.test.tsx b/src/test/components/navigation-and-footer.test.tsx
new file mode 100644
index 0000000..ef18832
--- /dev/null
+++ b/src/test/components/navigation-and-footer.test.tsx
@@ -0,0 +1,158 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter, useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import Footer from "@/components/Footer";
+import GroupSwitch from "@/components/GroupSwitch";
+import {
+ ServerDetailChartLoading,
+ ServerDetailLoading,
+} from "@/components/loading/ServerDetailLoading";
+import TabSwitch from "@/components/TabSwitch";
+import { createTestQueryClient, renderWithProviders } from "@/test/utils";
+
+const apiMocks = vi.hoisted(() => ({
+ fetchSetting: vi.fn(),
+}));
+
+vi.mock("@/lib/nezha-api", () => apiMocks);
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+describe("Footer", () => {
+ beforeEach(() => {
+ apiMocks.fetchSetting.mockResolvedValue({
+ success: true,
+ data: {
+ config: {
+ debug: false,
+ language: "en-US",
+ site_name: "Nezha",
+ user_template: "",
+ admin_template: "",
+ custom_code: "",
+ },
+ version: "9.9.9",
+ },
+ });
+ });
+
+ it("renders setting version and project attribution", async () => {
+ renderWithProviders();
+
+ expect(screen.getByText("footer.themeBy")).toBeInTheDocument();
+ expect(screen.getByText("nezha-dash")).toHaveAttribute(
+ "href",
+ "https://github.com/hamster1963/nezha-dash",
+ );
+ expect(await screen.findByText("9.9.9")).toBeInTheDocument();
+ });
+});
+
+describe("Tab and group switches", () => {
+ it("switches tabs and marks the active tab", async () => {
+ const user = userEvent.setup();
+ const setCurrentTab = vi.fn();
+
+ render(
+ ,
+ );
+
+ await user.click(screen.getByText("tabSwitch.Network"));
+
+ expect(setCurrentTab).toHaveBeenCalledWith("Network");
+ expect(
+ screen.getByText("tabSwitch.Detail").parentElement?.parentElement,
+ ).toHaveClass("text-black");
+ });
+
+ it("restores saved groups and hides itself when only All exists", async () => {
+ const setCurrentTab = vi.fn();
+ sessionStorage.setItem("selectedGroup", "Edge");
+
+ const { container, rerender } = render(
+ ,
+ );
+
+ await waitFor(() => {
+ expect(setCurrentTab).toHaveBeenCalledWith("Edge");
+ });
+
+ rerender(
+ ,
+ );
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
+ it("scrolls overflowing group tabs and applies custom background styling", async () => {
+ const user = userEvent.setup();
+ const setCurrentTab = vi.fn();
+ vi.spyOn(HTMLElement.prototype, "scrollWidth", "get").mockReturnValue(320);
+ vi.spyOn(HTMLElement.prototype, "clientWidth", "get").mockReturnValue(120);
+ window.CustomBackgroundImage = "/background.jpg";
+
+ const { container } = render(
+ ,
+ );
+
+ const scrollContainer = container.querySelector(
+ ".scrollbar-hidden",
+ ) as HTMLElement;
+
+ fireEvent.wheel(scrollContainer, { deltaY: 42 });
+ await user.click(screen.getByText("Asia"));
+
+ expect(scrollContainer.scrollLeft).toBe(42);
+ expect(setCurrentTab).toHaveBeenCalledWith("Asia");
+ expect(
+ container.querySelector(".relative.flex.items-center")?.className,
+ ).toContain("bg-stone-100/70");
+ });
+});
+
+describe("server detail loading states", () => {
+ it("renders chart skeleton cards", () => {
+ const { container } = render();
+
+ expect(container.querySelectorAll(".h-\\[182px\\]")).toHaveLength(6);
+ });
+
+ it("navigates home from the detail loading back affordance", async () => {
+ const user = userEvent.setup();
+ const queryClient = createTestQueryClient();
+
+ render(
+
+
+
+
+
+ ,
+ );
+
+ await user.click(screen.getAllByAltText("BackIcon")[0]);
+
+ expect(screen.getByText("/")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/network-chart.test.tsx b/src/test/components/network-chart.test.tsx
new file mode 100644
index 0000000..7c3c677
--- /dev/null
+++ b/src/test/components/network-chart.test.tsx
@@ -0,0 +1,287 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import type { ReactElement, ReactNode } from "react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import { NetworkChart, NetworkChartClient } from "@/components/NetworkChart";
+import type { ChartConfig } from "@/components/ui/chart";
+import { createTestQueryClient } from "@/test/utils";
+import type { NezhaMonitor, ServerMonitorChart } from "@/types/nezha-api";
+
+const apiMocks = vi.hoisted(() => ({
+ fetchLoginUser: vi.fn(),
+ fetchMonitor: vi.fn(),
+}));
+
+vi.mock("@/lib/nezha-api", () => ({
+ fetchLoginUser: apiMocks.fetchLoginUser,
+ fetchMonitor: apiMocks.fetchMonitor,
+}));
+
+vi.mock("recharts", () => {
+ const createElement =
+ (testId: string) =>
+ ({
+ children,
+ data,
+ dataKey,
+ }: {
+ children?: ReactNode;
+ data?: unknown[];
+ dataKey?: string;
+ }) => (
+
+ {children}
+
+ );
+
+ const ComposedChart = createElement("composed-chart");
+ const genericChart = createElement("generic-chart");
+
+ return {
+ Area: createElement("area"),
+ AreaChart: genericChart,
+ BarChart: genericChart,
+ CartesianGrid: createElement("grid"),
+ ComposedChart,
+ FunnelChart: genericChart,
+ Legend: ({ content }: { content?: ReactNode }) => (
+ {content}
+ ),
+ Line: createElement("line"),
+ LineChart: genericChart,
+ PieChart: genericChart,
+ RadarChart: genericChart,
+ RadialBarChart: genericChart,
+ ResponsiveContainer: ({ children }: { children?: ReactNode }) => (
+ {children}
+ ),
+ Sankey: genericChart,
+ ScatterChart: genericChart,
+ Tooltip: ({ content }: { content?: ReactNode }) => (
+ {content}
+ ),
+ Treemap: genericChart,
+ XAxis: createElement("x-axis"),
+ YAxis: createElement("y-axis"),
+ };
+});
+
+const times = Array.from(
+ { length: 12 },
+ (_, index) => Date.parse("2025-01-01T00:00:00.000Z") + index * 60 * 60 * 1000,
+);
+
+const monitorData: NezhaMonitor[] = [
+ {
+ monitor_id: 2,
+ monitor_name: "Beta",
+ display_index: 1,
+ server_id: 7,
+ server_name: "edge-chart",
+ created_at: times,
+ avg_delay: [15, 18, 0, 45, 48, 52, 4000, 65, 70, 75, 80, 85],
+ },
+ {
+ monitor_id: 1,
+ monitor_name: "Alpha",
+ display_index: 3,
+ server_id: 7,
+ server_name: "edge-chart",
+ created_at: times,
+ avg_delay: [30, 32, 35, 36, 38, 40, 42, 44, 46, 48, 50, 52],
+ packet_loss: [0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5],
+ },
+];
+
+const clientChartData: ServerMonitorChart = {
+ Alpha: times.map((created_at, index) => ({
+ created_at,
+ avg_delay: 30 + index,
+ packet_loss: index,
+ })),
+ Beta: times.map((created_at, index) => ({
+ created_at,
+ avg_delay: 60 + index,
+ packet_loss: index % 2,
+ })),
+};
+
+const clientFormattedData = times.map((created_at, index) => ({
+ created_at,
+ Alpha: 30 + index,
+ Alpha_packet_loss: index,
+ Beta: 60 + index,
+ Beta_packet_loss: index % 2,
+}));
+
+const chartConfig = {
+ avg_delay: { label: "monitor.avgDelay" },
+ Alpha: { label: "Alpha" },
+ Beta: { label: "Beta" },
+} satisfies ChartConfig;
+
+function loginResponse() {
+ return {
+ success: true,
+ data: {
+ id: 1,
+ username: "admin",
+ password: "",
+ created_at: "2025-01-01T00:00:00.000Z",
+ updated_at: "2025-01-01T00:00:00.000Z",
+ },
+ };
+}
+
+function renderWithQuery(ui: ReactElement) {
+ return render(
+
+ {ui}
+ ,
+ );
+}
+
+describe("NetworkChart", () => {
+ beforeEach(() => {
+ apiMocks.fetchLoginUser.mockReset();
+ apiMocks.fetchMonitor.mockReset();
+ apiMocks.fetchLoginUser.mockRejectedValue(new Error("anonymous"));
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "",
+ });
+ });
+
+ it("renders the loading state while monitor data is unavailable", () => {
+ apiMocks.fetchMonitor.mockReturnValue(new Promise(() => undefined));
+
+ const { container } = renderWithQuery(
+ ,
+ );
+
+ expect(container.querySelector(".h-\\[250px\\]")).toBeInTheDocument();
+ expect(apiMocks.fetchMonitor).not.toHaveBeenCalled();
+ });
+
+ it("renders the no-data state from the monitor API", async () => {
+ apiMocks.fetchMonitor.mockResolvedValue({
+ success: true,
+ data: null,
+ });
+
+ renderWithQuery();
+
+ expect(await screen.findByText("monitor.noData")).toBeInTheDocument();
+ });
+
+ it("fetches monitor data, transforms chart series, and allows logged-in period changes", async () => {
+ const user = userEvent.setup();
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "session=1",
+ });
+ apiMocks.fetchLoginUser.mockResolvedValue(loginResponse());
+ apiMocks.fetchMonitor.mockResolvedValue({
+ success: true,
+ data: monitorData,
+ });
+
+ renderWithQuery();
+
+ expect(await screen.findByText("edge-chart")).toBeInTheDocument();
+ expect(apiMocks.fetchMonitor).toHaveBeenCalledWith(7, "1d");
+ expect(screen.getByText("2 monitor.monitorCount")).toBeInTheDocument();
+ expect(screen.getByText("Alpha")).toBeInTheDocument();
+ expect(screen.getByText("Beta")).toBeInTheDocument();
+ expect(screen.getByTestId("composed-chart")).toHaveAttribute(
+ "data-points",
+ "12",
+ );
+
+ await user.click(screen.getByText("monitor.period7d"));
+
+ await waitFor(() => {
+ expect(apiMocks.fetchMonitor).toHaveBeenCalledWith(7, "7d");
+ });
+ });
+});
+
+describe("NetworkChartClient", () => {
+ it("locks longer periods for anonymous users and manages chart selection state", async () => {
+ const user = userEvent.setup();
+ const onPeriodChange = vi.fn();
+
+ render(
+ ,
+ );
+
+ expect(screen.getByText("edge-client")).toBeInTheDocument();
+ expect(screen.getByText("2 monitor.monitorCount")).toBeInTheDocument();
+
+ await user.click(screen.getByText("monitor.period7d"));
+ expect(onPeriodChange).not.toHaveBeenCalled();
+
+ await user.click(screen.getByText("Alpha"));
+ expect(
+ screen.getByRole("button", { name: /monitor.clearSelections/ }),
+ ).toBeInTheDocument();
+ expect(screen.getByTestId("area")).toHaveAttribute(
+ "data-key",
+ "packet_loss",
+ );
+
+ await user.click(screen.getByText("Beta"));
+ expect(screen.queryByTestId("area")).not.toBeInTheDocument();
+
+ await user.click(
+ screen.getByRole("button", { name: /monitor.clearSelections/ }),
+ );
+ expect(
+ screen.queryByRole("button", { name: /monitor.clearSelections/ }),
+ ).not.toBeInTheDocument();
+ });
+
+ it("shows period loading and honors the forced peak-cut global", async () => {
+ const user = userEvent.setup();
+ Object.assign(window, { ForcePeakCutEnabled: true });
+ const onPeriodChange = vi.fn();
+
+ const { container } = render(
+ ,
+ );
+
+ expect(container.querySelector(".opacity-60")).toBeInTheDocument();
+ expect(
+ screen.getByRole("switch", { name: "monitor.peakCut" }),
+ ).toHaveAttribute("data-state", "checked");
+
+ await user.click(screen.getByText("monitor.period30d"));
+ expect(onPeriodChange).toHaveBeenCalledWith("30d");
+
+ await user.click(screen.getByRole("switch", { name: "monitor.peakCut" }));
+ expect(
+ screen.getByRole("switch", { name: "monitor.peakCut" }),
+ ).toHaveAttribute("data-state", "unchecked");
+ });
+});
diff --git a/src/test/components/server-cards.test.tsx b/src/test/components/server-cards.test.tsx
new file mode 100644
index 0000000..45de958
--- /dev/null
+++ b/src/test/components/server-cards.test.tsx
@@ -0,0 +1,148 @@
+import { fireEvent, screen } from "@testing-library/react";
+import { useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import ServerCard from "@/components/ServerCard";
+import ServerCardInline from "@/components/ServerCardInline";
+import { createServer } from "@/test/fixtures";
+import { renderWithProviders } from "@/test/utils";
+
+const publicNote = JSON.stringify({
+ billingDataMod: {
+ startDate: "2025-01-01T00:00:00.000Z",
+ endDate: "2025-01-31T00:00:00.000Z",
+ autoRenewal: "0",
+ cycle: "monthly",
+ amount: "10",
+ },
+ planDataMod: {
+ bandwidth: "1Gbps",
+ trafficVol: "2TB",
+ trafficType: "monthly",
+ IPv4: "1",
+ IPv6: "1",
+ networkRoute: "CN2,CMI",
+ extra: "Premium",
+ },
+});
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+describe("ServerCard", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.setSystemTime(new Date("2025-01-15T00:00:00.000Z"));
+ Object.assign(window, {
+ ForceUseSvgFlag: true,
+ FixedTopServerName: true,
+ ShowNetTransfer: true,
+ });
+ });
+
+ it("renders online server metrics, billing, plan data, and navigates on click", async () => {
+ const server = createServer({
+ id: 7,
+ name: "edge-online",
+ public_note: publicNote,
+ host: { platform: "Windows Server" },
+ });
+
+ renderWithProviders(
+ <>
+
+
+ >,
+ );
+
+ expect(screen.getByText("edge-online")).toBeInTheDocument();
+ expect(screen.getByText("Windows")).toBeInTheDocument();
+ expect(screen.getByText("12.00%")).toBeInTheDocument();
+ expect(screen.getAllByText("25.00%")).toHaveLength(2);
+ expect(screen.getByText("serverCard.upload:2.00 GiB")).toBeInTheDocument();
+ expect(
+ screen.getByText("serverCard.download:1.00 GiB"),
+ ).toBeInTheDocument();
+ expect(screen.getByText("1Gbps")).toBeInTheDocument();
+ expect(
+ screen.getAllByText(/billingInfo.remaining: 16/).length,
+ ).toBeGreaterThan(0);
+
+ fireEvent.click(screen.getByText("edge-online"));
+
+ expect(sessionStorage.getItem("fromMainPage")).toBe("true");
+ expect(screen.getByText("/server/7")).toBeInTheDocument();
+ });
+
+ it("renders a compact offline card without live metric blocks", () => {
+ const server = createServer({
+ id: 8,
+ name: "edge-offline",
+ public_note: publicNote,
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+
+ renderWithProviders(
+ ,
+ );
+
+ expect(screen.getByText("edge-offline")).toBeInTheDocument();
+ expect(screen.getByText("1Gbps")).toBeInTheDocument();
+ expect(screen.queryByText("CPU")).not.toBeInTheDocument();
+ });
+});
+
+describe("ServerCardInline", () => {
+ beforeEach(() => {
+ Object.assign(window, { ForceUseSvgFlag: true });
+ });
+
+ it("renders online inline server detail columns", () => {
+ const server = createServer({
+ id: 9,
+ name: "edge-inline",
+ public_note: publicNote,
+ state: { uptime: 2 * 86_400 },
+ });
+
+ renderWithProviders(
+ ,
+ );
+
+ expect(screen.getByText("edge-inline")).toBeInTheDocument();
+ expect(screen.getByText("serverCard.system")).toBeInTheDocument();
+ expect(screen.getByText("2 serverCard.days")).toBeInTheDocument();
+ expect(screen.getByText("2.00 GiB")).toBeInTheDocument();
+ expect(screen.getByText("1.00 GiB")).toBeInTheDocument();
+ });
+
+ it("renders offline inline server cards with saved plan data", () => {
+ const server = createServer({
+ id: 10,
+ name: "edge-inline-offline",
+ public_note: publicNote,
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+
+ renderWithProviders(
+ ,
+ );
+
+ expect(screen.getByText("edge-inline-offline")).toBeInTheDocument();
+ expect(screen.getByText("1Gbps")).toBeInTheDocument();
+ expect(screen.queryByText("serverCard.system")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/server-detail-chart.test.tsx b/src/test/components/server-detail-chart.test.tsx
new file mode 100644
index 0000000..29b3bb0
--- /dev/null
+++ b/src/test/components/server-detail-chart.test.tsx
@@ -0,0 +1,290 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import type { ReactNode } from "react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import ServerDetailChart from "@/components/ServerDetailChart";
+import { createServer, createSettingResponse } from "@/test/fixtures";
+import { createTestQueryClient } from "@/test/utils";
+import type { NezhaServer } from "@/types/nezha-api";
+
+const detailChartMocks = vi.hoisted(() => ({
+ connected: true,
+ fetchLoginUser: vi.fn(),
+ fetchServerMetrics: vi.fn(),
+ fetchSetting: vi.fn(),
+ lastMessage: null as { data: string } | null,
+ messageHistory: [] as { data: string }[],
+}));
+
+vi.mock("recharts", () => {
+ const createElement =
+ (testId: string) =>
+ ({
+ children,
+ data,
+ dataKey,
+ }: {
+ children?: ReactNode;
+ data?: unknown[];
+ dataKey?: string;
+ }) => (
+
+ {children}
+
+ );
+
+ const AreaChart = createElement("area-chart");
+ const LineChart = createElement("line-chart");
+ const genericChart = createElement("generic-chart");
+
+ return {
+ Area: createElement("area"),
+ AreaChart,
+ BarChart: genericChart,
+ CartesianGrid: createElement("grid"),
+ ComposedChart: genericChart,
+ FunnelChart: genericChart,
+ Legend: ({ content }: { content?: ReactNode }) => (
+ {content}
+ ),
+ Line: createElement("line"),
+ LineChart,
+ PieChart: genericChart,
+ RadarChart: genericChart,
+ RadialBarChart: genericChart,
+ ResponsiveContainer: ({ children }: { children?: ReactNode }) => (
+ {children}
+ ),
+ Sankey: genericChart,
+ ScatterChart: genericChart,
+ Tooltip: ({ content }: { content?: ReactNode }) => (
+ {content}
+ ),
+ Treemap: genericChart,
+ XAxis: createElement("x-axis"),
+ YAxis: createElement("y-axis"),
+ };
+});
+
+vi.mock("@/hooks/use-websocket-context", () => ({
+ useWebSocketContext: () => ({
+ connected: detailChartMocks.connected,
+ lastMessage: detailChartMocks.lastMessage,
+ messageHistory: detailChartMocks.messageHistory,
+ }),
+}));
+
+vi.mock("@/lib/nezha-api", () => ({
+ fetchLoginUser: detailChartMocks.fetchLoginUser,
+ fetchServerMetrics: detailChartMocks.fetchServerMetrics,
+ fetchSetting: detailChartMocks.fetchSetting,
+}));
+
+function settingResponse(tsdbEnabled = true) {
+ return {
+ ...createSettingResponse(),
+ data: {
+ ...createSettingResponse().data,
+ tsdb_enabled: tsdbEnabled,
+ },
+ };
+}
+
+function loginResponse() {
+ return {
+ success: true,
+ data: {
+ id: 1,
+ username: "admin",
+ password: "",
+ created_at: "2025-01-01T00:00:00.000Z",
+ updated_at: "2025-01-01T00:00:00.000Z",
+ },
+ };
+}
+
+function metricsResponse(metric: string) {
+ return {
+ success: true,
+ data: {
+ server_id: 7,
+ server_name: "edge-chart-detail",
+ metric,
+ data_points: [
+ { ts: Date.parse("2025-01-01T00:00:00.000Z"), value: 10 },
+ { ts: Date.parse("2025-01-01T01:00:00.000Z"), value: 20 },
+ { ts: Date.parse("2025-01-01T02:00:00.000Z"), value: 30 },
+ ],
+ },
+ };
+}
+
+function websocketPayload(server: NezhaServer, now: number) {
+ return {
+ data: JSON.stringify({
+ now,
+ servers: [server],
+ }),
+ };
+}
+
+function renderWithQuery(ui: React.ReactElement) {
+ return render(
+
+ {ui}
+ ,
+ );
+}
+
+function seedWebSocketData() {
+ const baseNow = Date.parse("2025-01-01T00:00:20.000Z");
+ const server = createServer({
+ id: 7,
+ name: "edge-chart-detail",
+ host: {
+ gpu: ["NVIDIA T4"],
+ },
+ state: {
+ cpu: 45,
+ disk_used: 180,
+ gpu: [33],
+ mem_used: 80,
+ net_in_speed: 4 * 1024 ** 2,
+ net_out_speed: 3 * 1024 ** 2,
+ process_count: 77,
+ swap_used: 25,
+ tcp_conn_count: 18,
+ udp_conn_count: 9,
+ },
+ });
+
+ detailChartMocks.connected = true;
+ detailChartMocks.lastMessage = websocketPayload(server, baseNow);
+ detailChartMocks.messageHistory = [0, 1, 2].map((index) =>
+ websocketPayload(
+ createServer({
+ id: 7,
+ host: {
+ gpu: ["NVIDIA T4"],
+ },
+ state: {
+ cpu: 30 + index,
+ disk_used: 100 + index * 10,
+ gpu: [20 + index],
+ mem_used: 50 + index * 5,
+ net_in_speed: (1 + index) * 1024 ** 2,
+ net_out_speed: (2 + index) * 1024 ** 2,
+ process_count: 60 + index,
+ swap_used: 10 + index,
+ tcp_conn_count: 10 + index,
+ udp_conn_count: 5 + index,
+ },
+ }),
+ baseNow - index * 1000,
+ ),
+ );
+}
+
+describe("ServerDetailChart", () => {
+ beforeEach(() => {
+ detailChartMocks.connected = true;
+ detailChartMocks.fetchLoginUser.mockReset();
+ detailChartMocks.fetchServerMetrics.mockReset();
+ detailChartMocks.fetchSetting.mockReset();
+ detailChartMocks.lastMessage = null;
+ detailChartMocks.messageHistory = [];
+ detailChartMocks.fetchLoginUser.mockRejectedValue(new Error("anonymous"));
+ detailChartMocks.fetchSetting.mockResolvedValue(settingResponse());
+ });
+
+ it("renders the loading grid without websocket data", () => {
+ detailChartMocks.connected = false;
+
+ const { container } = renderWithQuery();
+
+ expect(container.querySelectorAll(".h-\\[182px\\]")).toHaveLength(6);
+ });
+
+ it("renders realtime resource, network, connection, and GPU charts", async () => {
+ const user = userEvent.setup();
+ seedWebSocketData();
+
+ renderWithQuery();
+
+ expect(
+ await screen.findByText("serverDetailChart.realtime"),
+ ).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.period1d")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.period7d")).toBeInTheDocument();
+ expect(screen.getByText("CPU")).toBeInTheDocument();
+ expect(screen.getByText("GPU: NVIDIA T4")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.mem")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.swap")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.disk")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.process")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.upload")).toBeInTheDocument();
+ expect(screen.getByText("serverDetailChart.download")).toBeInTheDocument();
+ expect(screen.getByText("TCP")).toBeInTheDocument();
+ expect(screen.getByText("UDP")).toBeInTheDocument();
+ expect(screen.getAllByTestId("area-chart").length).toBeGreaterThan(0);
+ expect(screen.getAllByTestId("line-chart").length).toBeGreaterThan(0);
+
+ await user.click(screen.getByText("serverDetailChart.period7d"));
+
+ expect(detailChartMocks.fetchServerMetrics).not.toHaveBeenCalled();
+ });
+
+ it("prevents historical periods when TSDB is disabled", async () => {
+ const user = userEvent.setup();
+ seedWebSocketData();
+ detailChartMocks.fetchSetting.mockResolvedValue(settingResponse(false));
+
+ renderWithQuery();
+
+ await screen.findByText("serverDetailChart.realtime");
+ await user.click(screen.getByText("serverDetailChart.period1d"));
+
+ expect(detailChartMocks.fetchServerMetrics).not.toHaveBeenCalled();
+ });
+
+ it("fetches every historical metric group for the selected period", async () => {
+ const user = userEvent.setup();
+ seedWebSocketData();
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "session=1",
+ });
+ detailChartMocks.fetchLoginUser.mockResolvedValue(loginResponse());
+ detailChartMocks.fetchServerMetrics.mockImplementation(
+ (_serverId: number, metric: string) =>
+ Promise.resolve(metricsResponse(metric)),
+ );
+
+ renderWithQuery();
+
+ await screen.findByText("serverDetailChart.realtime");
+ await user.click(screen.getByText("serverDetailChart.period1d"));
+
+ for (const metric of [
+ "cpu",
+ "gpu",
+ "memory",
+ "swap",
+ "disk",
+ "process_count",
+ "net_out_speed",
+ "net_in_speed",
+ "tcp_conn",
+ "udp_conn",
+ ]) {
+ await waitFor(() => {
+ expect(detailChartMocks.fetchServerMetrics).toHaveBeenCalledWith(
+ 7,
+ metric,
+ "1d",
+ );
+ });
+ }
+ });
+});
diff --git a/src/test/components/server-detail-components.test.tsx b/src/test/components/server-detail-components.test.tsx
new file mode 100644
index 0000000..8b6d526
--- /dev/null
+++ b/src/test/components/server-detail-components.test.tsx
@@ -0,0 +1,138 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter, useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import ServerDetailOverview from "@/components/ServerDetailOverview";
+import ServerDetailSummary from "@/components/ServerDetailSummary";
+import { createServer } from "@/test/fixtures";
+
+const websocketMocks = vi.hoisted(() => ({
+ connected: true,
+ lastMessage: null as MessageEvent | null,
+}));
+
+vi.mock("@/hooks/use-websocket-context", () => ({
+ useWebSocketContext: () => websocketMocks,
+}));
+
+function seedWebSocketData({
+ server = createServer(),
+ now = Date.parse("2025-01-01T00:00:20.000Z"),
+} = {}) {
+ websocketMocks.connected = true;
+ websocketMocks.lastMessage = new MessageEvent("message", {
+ data: JSON.stringify({
+ now,
+ servers: [server],
+ }),
+ });
+}
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+describe("ServerDetailSummary", () => {
+ beforeEach(() => {
+ websocketMocks.connected = true;
+ websocketMocks.lastMessage = null;
+ });
+
+ it("renders nothing until websocket data exists", () => {
+ websocketMocks.connected = false;
+
+ const { container } = render();
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
+ it("renders resource, network, and connection summaries for the selected server", () => {
+ seedWebSocketData();
+
+ render();
+
+ expect(screen.getByText("12.00%")).toBeInTheDocument();
+ expect(screen.getAllByText("25.00%")).toHaveLength(2);
+ expect(screen.getByText("Process")).toBeInTheDocument();
+ expect(screen.getByText("88")).toBeInTheDocument();
+ expect(screen.getByText("TCP")).toBeInTheDocument();
+ expect(screen.getByText("8")).toBeInTheDocument();
+ expect(screen.getByText("UDP")).toBeInTheDocument();
+ expect(screen.getByText("4")).toBeInTheDocument();
+ expect(screen.getByText("1.00M/s")).toBeInTheDocument();
+ expect(screen.getByText("2.00M/s")).toBeInTheDocument();
+ });
+});
+
+describe("ServerDetailOverview", () => {
+ beforeEach(() => {
+ websocketMocks.connected = true;
+ websocketMocks.lastMessage = null;
+ Object.assign(window, { ForceUseSvgFlag: true });
+ });
+
+ it("shows the loading shell when websocket data or the selected server is missing", () => {
+ websocketMocks.connected = false;
+ const { rerender } = render(
+
+
+ ,
+ );
+
+ expect(screen.getAllByAltText("BackIcon").length).toBeGreaterThan(0);
+
+ seedWebSocketData();
+ rerender(
+
+
+ ,
+ );
+
+ expect(screen.getAllByAltText("BackIcon").length).toBeGreaterThan(0);
+ });
+
+ it("renders server identity, hardware, traffic, and temperature details", async () => {
+ const user = userEvent.setup();
+ seedWebSocketData({
+ server: createServer({
+ id: 7,
+ name: "edge-detail",
+ country_code: "us",
+ host: {
+ gpu: ["NVIDIA T4"],
+ },
+ state: {
+ temperatures: [{ Name: "CPU Core", Temperature: 55.5 }],
+ },
+ }),
+ });
+
+ render(
+
+
+
+ ,
+ );
+
+ expect(screen.getByText("edge-detail")).toBeInTheDocument();
+ expect(screen.getByText("serverDetail.online")).toBeInTheDocument();
+ expect(screen.getByText("1.0.0")).toBeInTheDocument();
+ expect(screen.getByText("amd64")).toBeInTheDocument();
+ expect(screen.getByText("US")).toBeInTheDocument();
+ expect(screen.getByText(/linux - 6.8/)).toBeInTheDocument();
+ expect(screen.getByText(/AMD EPYC/)).toBeInTheDocument();
+ expect(screen.getByText("NVIDIA T4")).toBeInTheDocument();
+ expect(screen.getByText("2.00 GiB")).toBeInTheDocument();
+ expect(screen.getByText("1.00 GiB")).toBeInTheDocument();
+
+ await user.click(
+ screen.getByRole("button", { name: /serverDetail.temperature/ }),
+ );
+ expect(screen.getByText("CPU Core")).toBeInTheDocument();
+ expect(screen.getByText(/55.50 °C/)).toBeInTheDocument();
+
+ await user.click(screen.getByText("edge-detail"));
+ expect(screen.getByText("/")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/service-tracker.test.tsx b/src/test/components/service-tracker.test.tsx
new file mode 100644
index 0000000..87c8aee
--- /dev/null
+++ b/src/test/components/service-tracker.test.tsx
@@ -0,0 +1,249 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import { CycleTransferStatsCard } from "@/components/CycleTransferStats";
+import CycleTransferStatsClient from "@/components/CycleTransferStatsClient";
+import { ServiceTracker } from "@/components/ServiceTracker";
+import ServiceTrackerClient from "@/components/ServiceTrackerClient";
+import { createServer } from "@/test/fixtures";
+import { createTestQueryClient } from "@/test/utils";
+
+const apiMocks = vi.hoisted(() => ({
+ fetchService: vi.fn(),
+}));
+
+vi.mock("@/lib/nezha-api", () => apiMocks);
+
+function renderWithQuery(ui: React.ReactElement) {
+ return render(
+
+ {ui}
+ ,
+ );
+}
+
+describe("ServiceTracker", () => {
+ it("shows the loading state while service data is pending", () => {
+ apiMocks.fetchService.mockReturnValue(new Promise(() => undefined));
+
+ renderWithQuery();
+
+ expect(screen.getByText("serviceTracker.loading")).toBeInTheDocument();
+ });
+
+ it("shows an empty state when there are no services or cycle stats", async () => {
+ apiMocks.fetchService.mockResolvedValue({
+ success: true,
+ data: {},
+ });
+
+ renderWithQuery();
+
+ expect(
+ await screen.findByText("serviceTracker.noService"),
+ ).toBeInTheDocument();
+ });
+
+ it("renders processed service uptime, delay, and matching cycle transfer stats", async () => {
+ apiMocks.fetchService.mockResolvedValue({
+ success: true,
+ data: {
+ services: {
+ http: {
+ service_name: "HTTP Ping",
+ current_up: 0,
+ current_down: 0,
+ total_up: 5,
+ total_down: 3,
+ delay: [80, 120, 450],
+ up: [3, 2, 0],
+ down: [0, 1, 2],
+ },
+ },
+ cycle_transfer_stats: {
+ monthly: {
+ name: "Monthly",
+ from: "2025-01-01T00:00:00.000Z",
+ to: "2025-02-01T00:00:00.000Z",
+ max: 10 * 1024,
+ min: 0,
+ server_name: {
+ "1": "edge-1",
+ "2": "hidden-server",
+ },
+ transfer: {
+ "1": 5 * 1024,
+ "2": 1024,
+ },
+ next_update: {
+ "1": "2025-01-15T12:00:00.000Z",
+ "2": "2025-01-15T12:00:00.000Z",
+ },
+ },
+ },
+ },
+ });
+
+ renderWithQuery();
+
+ expect(await screen.findByText("HTTP Ping")).toBeInTheDocument();
+ expect(screen.getByText("217ms")).toBeInTheDocument();
+ expect(screen.getByText("62.5% serviceTracker.uptime")).toBeInTheDocument();
+ expect(screen.getByText("edge-1")).toBeInTheDocument();
+ expect(screen.getByText("Monthly")).toBeInTheDocument();
+ expect(screen.queryByText("hidden-server")).not.toBeInTheDocument();
+ });
+});
+
+describe("CycleTransferStatsCard", () => {
+ it("renders nothing for empty server lists", () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
+ it("supports per-server date and max maps while skipping incomplete entries", () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByText("edge-7")).toBeInTheDocument();
+ expect(screen.getByText("Mapped")).toBeInTheDocument();
+ expect(screen.queryByText("edge-8")).not.toBeInTheDocument();
+ expect(screen.queryByText("missing-fields")).not.toBeInTheDocument();
+ });
+});
+
+describe("ServiceTrackerClient and CycleTransferStatsClient", () => {
+ it("uses uptime and delay severity colors for service summaries", () => {
+ const days = [
+ {
+ completed: true,
+ date: new Date("2025-01-01T00:00:00.000Z"),
+ uptime: 99.5,
+ delay: 80,
+ },
+ {
+ completed: false,
+ date: new Date("2025-01-02T00:00:00.000Z"),
+ uptime: 90,
+ delay: 320,
+ },
+ ];
+
+ const { rerender } = render(
+ ,
+ );
+
+ expect(screen.getByText("99.9% serviceTracker.uptime")).toHaveClass(
+ "text-emerald-500",
+ );
+ expect(screen.getByText("80ms")).toHaveClass("text-emerald-500");
+
+ rerender(
+ ,
+ );
+
+ expect(screen.getByText("97.0% serviceTracker.uptime")).toHaveClass(
+ "text-amber-500",
+ );
+ expect(screen.getByText("180ms")).toHaveClass("text-amber-500");
+
+ rerender(
+ ,
+ );
+
+ expect(screen.getByText("94.0% serviceTracker.uptime")).toHaveClass(
+ "text-rose-500",
+ );
+ expect(screen.getByText("320ms")).toHaveClass("text-rose-500");
+ });
+
+ it("caps cycle transfer progress at one hundred percent", () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(screen.getByText("200.0%")).toBeInTheDocument();
+ expect(
+ container.querySelector('[style="width: 100%;"]'),
+ ).toBeInTheDocument();
+ });
+});
diff --git a/src/test/components/switchers-and-primitives.test.tsx b/src/test/components/switchers-and-primitives.test.tsx
new file mode 100644
index 0000000..efeec97
--- /dev/null
+++ b/src/test/components/switchers-and-primitives.test.tsx
@@ -0,0 +1,291 @@
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+import { LanguageSwitcher } from "@/components/LanguageSwitcher";
+import { ThemeProvider } from "@/components/ThemeProvider";
+import { ModeToggle } from "@/components/ThemeSwitcher";
+import {
+ Accordion,
+ AccordionContent,
+ AccordionItem,
+ AccordionTrigger,
+} from "@/components/ui/accordion";
+import { Checkbox } from "@/components/ui/checkbox";
+import {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import {
+ DropdownMenu,
+ DropdownMenuCheckboxItem,
+ DropdownMenuContent,
+ DropdownMenuGroup,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuSeparator,
+ DropdownMenuShortcut,
+ DropdownMenuSub,
+ DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
+import { Label } from "@/components/ui/label";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectLabel,
+ SelectSeparator,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import { Switch } from "@/components/ui/switch";
+import {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip";
+
+describe("language and theme switchers", () => {
+ it("opens the language menu and marks the active locale", async () => {
+ const user = userEvent.setup();
+
+ render();
+
+ await user.click(screen.getByRole("button", { name: "Change language" }));
+
+ expect(screen.getByText("language.zh-CN")).toBeInTheDocument();
+ expect(screen.getByText("language.en-US")).toHaveClass("font-semibold");
+ });
+
+ it("updates the theme through the mode menu", async () => {
+ const user = userEvent.setup();
+
+ render(
+
+
+ ,
+ );
+
+ await user.click(screen.getByRole("button", { name: "Toggle theme" }));
+ await user.click(await screen.findByText("theme.dark"));
+
+ expect(document.documentElement).toHaveClass("dark");
+ expect(localStorage.getItem("theme-switcher-test")).toBe("dark");
+ });
+});
+
+describe("Radix UI wrappers", () => {
+ it("opens accordion, popover, tooltip, and dialog content", async () => {
+ const user = userEvent.setup();
+
+ render(
+ <>
+
+
+ Toggle status
+ Status body
+
+
+
+ Open popover
+ Popover body
+
+
+
+ Hover status
+ Tooltip body
+
+
+
+ >,
+ );
+
+ await user.click(screen.getByRole("button", { name: "Toggle status" }));
+ expect(screen.getByText("Status body")).toBeInTheDocument();
+
+ await user.click(screen.getByRole("button", { name: "Open popover" }));
+ expect(screen.getByText("Popover body")).toBeInTheDocument();
+
+ await user.hover(screen.getByText("Hover status"));
+ expect(await screen.findByRole("tooltip")).toHaveTextContent(
+ "Tooltip body",
+ );
+
+ await user.click(screen.getByRole("button", { name: "Open dialog" }));
+ expect(screen.getByText("Confirm action")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "Done" }));
+ await waitFor(() => {
+ expect(screen.queryByText("Confirm action")).not.toBeInTheDocument();
+ });
+ });
+
+ it("toggles checkbox and switch controls through labels", async () => {
+ const user = userEvent.setup();
+ const onCheckboxChange = vi.fn();
+ const onSwitchChange = vi.fn();
+
+ render(
+ <>
+
+
+
+ >,
+ );
+
+ await user.click(screen.getByText("Alerts"));
+ await user.click(screen.getByRole("switch", { name: "Compact mode" }));
+
+ expect(onCheckboxChange).toHaveBeenCalledWith(true);
+ expect(onSwitchChange).toHaveBeenCalledWith(true);
+ expect(screen.getByRole("checkbox")).toHaveAttribute(
+ "data-state",
+ "checked",
+ );
+ expect(
+ screen.getByRole("switch", { name: "Compact mode" }),
+ ).toHaveAttribute("data-state", "checked");
+ });
+
+ it("renders dropdown labels, indicators, shortcuts, and submenus", async () => {
+ render(
+
+ Open actions
+
+ Actions
+
+
+ Copy
+ Ctrl+C
+
+
+ Show hidden
+
+
+
+ Compact rows
+
+
+
+
+
+ More actions
+
+
+ Archive
+
+
+
+
+ ,
+ );
+
+ expect(await screen.findByText("Actions")).toHaveClass("pl-8");
+ expect(screen.getByText("Copy")).toHaveClass("pl-8");
+ expect(screen.getByText("Ctrl+C")).toHaveClass("tracking-widest");
+ expect(screen.getByText("Show hidden")).toHaveAttribute(
+ "data-state",
+ "checked",
+ );
+ expect(screen.getByText("Compact rows")).toHaveAttribute(
+ "data-state",
+ "checked",
+ );
+ expect(screen.getByText("More actions")).toHaveClass("pl-8");
+ expect(screen.getByText("Archive")).toBeInTheDocument();
+ });
+
+ it("selects values and renders table structure", async () => {
+ const user = userEvent.setup();
+ const onValueChange = vi.fn();
+
+ render(
+ <>
+
+
+ Server summary
+
+
+ Name
+ Status
+
+
+
+
+ edge-1
+ online
+
+
+
+
+ Total
+ 1
+
+
+
+ >,
+ );
+
+ await user.click(screen.getByRole("combobox", { name: "Region" }));
+ await user.click(await screen.findByRole("option", { name: "Asia" }));
+
+ expect(onValueChange).toHaveBeenCalledWith("asia");
+ expect(screen.getByText("Server summary")).toBeInTheDocument();
+ expect(
+ screen.getByRole("columnheader", { name: "Name" }),
+ ).toBeInTheDocument();
+ expect(screen.getByText("edge-1")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/context/providers.test.tsx b/src/test/context/providers.test.tsx
new file mode 100644
index 0000000..5e54cfd
--- /dev/null
+++ b/src/test/context/providers.test.tsx
@@ -0,0 +1,289 @@
+import { act, render, renderHook, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import type { ReactNode } from "react";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import { CommandProvider } from "@/context/command-provider";
+import { SortProvider } from "@/context/sort-provider";
+import { StatusProvider } from "@/context/status-provider";
+import { TooltipProvider } from "@/context/tooltip-provider";
+import { WebSocketProvider } from "@/context/websocket-provider";
+import { useCommand } from "@/hooks/use-command";
+import { useSort } from "@/hooks/use-sort";
+import { useStatus } from "@/hooks/use-status";
+import { useTooltip } from "@/hooks/use-tooltip";
+import { useWebSocketContext } from "@/hooks/use-websocket-context";
+
+class FakeWebSocket {
+ static readonly CONNECTING = 0;
+ static readonly OPEN = 1;
+ static readonly CLOSING = 2;
+ static readonly CLOSED = 3;
+ static instances: FakeWebSocket[] = [];
+
+ readonly url: string;
+ readyState = FakeWebSocket.CONNECTING;
+ onopen: ((event: Event) => void) | null = null;
+ onclose: ((event: CloseEvent) => void) | null = null;
+ onmessage: ((event: MessageEvent) => void) | null = null;
+ onerror: ((event: Event) => void) | null = null;
+
+ constructor(url: string) {
+ this.url = url;
+ FakeWebSocket.instances.push(this);
+ }
+
+ open() {
+ this.readyState = FakeWebSocket.OPEN;
+ this.onopen?.(new Event("open"));
+ }
+
+ message(data: string) {
+ this.onmessage?.(new MessageEvent("message", { data }));
+ }
+
+ close() {
+ this.readyState = FakeWebSocket.CLOSED;
+ this.onclose?.(new CloseEvent("close"));
+ }
+}
+
+function CommandProbe() {
+ const { closeCommand, isOpen, openCommand, toggleCommand } = useCommand();
+
+ return (
+
+
{isOpen ? "open" : "closed"}
+
+
+
+
+ );
+}
+
+function SortProbe() {
+ const { setSortOrder, setSortType, sortOrder, sortType } = useSort();
+
+ return (
+
+
{`${sortType}:${sortOrder}`}
+
+
+
+ );
+}
+
+function StatusProbe() {
+ const { setStatus, status } = useStatus();
+
+ return (
+
+
{status}
+
+
+ );
+}
+
+function TooltipProbe() {
+ const { setTooltipData, tooltipData } = useTooltip();
+
+ return (
+
+
{tooltipData?.country ?? "empty"}
+
+
+ );
+}
+
+function WebSocketProbe() {
+ const {
+ connected,
+ lastMessage,
+ messageHistory,
+ needReconnect,
+ setNeedReconnect,
+ } = useWebSocketContext();
+
+ return (
+
+
{connected ? "connected" : "disconnected"}
+
{lastMessage?.data ?? "none"}
+
{messageHistory.length}
+
{needReconnect ? "needs-reconnect" : "stable"}
+
+
+ );
+}
+
+describe("state providers", () => {
+ it("manages command palette open state", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByTestId("command-state")).toHaveTextContent("closed");
+ await user.click(screen.getByRole("button", { name: "open" }));
+ expect(screen.getByTestId("command-state")).toHaveTextContent("open");
+ await user.click(screen.getByRole("button", { name: "toggle" }));
+ expect(screen.getByTestId("command-state")).toHaveTextContent("closed");
+ await user.click(screen.getByRole("button", { name: "open" }));
+ await user.click(screen.getByRole("button", { name: "close" }));
+ expect(screen.getByTestId("command-state")).toHaveTextContent("closed");
+ });
+
+ it("uses forced sort globals when valid and still allows local updates", async () => {
+ window.ForceSortType = "mem";
+ window.ForceSortOrder = "asc";
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("mem:asc")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "cpu" }));
+ expect(screen.getByText("cpu:asc")).toBeInTheDocument();
+ });
+
+ it("falls back to default sort values for invalid forced globals", () => {
+ window.ForceSortType = "invalid";
+ window.ForceSortOrder = "up";
+
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("default:desc")).toBeInTheDocument();
+ });
+
+ it("manages server status filters", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByTestId("status-state")).toHaveTextContent("all");
+ await user.click(screen.getByRole("button", { name: "online" }));
+ expect(screen.getByTestId("status-state")).toHaveTextContent("online");
+ });
+
+ it("stores map tooltip data", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("empty")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "show" }));
+ expect(screen.getByText("China")).toBeInTheDocument();
+ });
+});
+
+describe("context hooks", () => {
+ it("throws helpful errors when strict hooks miss their providers", () => {
+ expect(() => renderHook(() => useCommand())).toThrow(
+ "useCommand must be used within a CommandProvider",
+ );
+ expect(() => renderHook(() => useSort())).toThrow(
+ "useStatus must be used within a SortProvider",
+ );
+ expect(() => renderHook(() => useStatus())).toThrow(
+ "useStatus must be used within a StatusProvider",
+ );
+ expect(() => renderHook(() => useTooltip())).toThrow(
+ "useTooltip must be used within a TooltipProvider",
+ );
+ });
+});
+
+describe("WebSocketProvider", () => {
+ beforeEach(() => {
+ FakeWebSocket.instances = [];
+ vi.stubGlobal("WebSocket", FakeWebSocket);
+ });
+
+ function renderWebSocketProvider(children: ReactNode) {
+ return render(
+ {children},
+ );
+ }
+
+ it("connects with a ws URL and records incoming messages", () => {
+ renderWebSocketProvider();
+
+ const socket = FakeWebSocket.instances[0];
+ expect(socket.url).toBe("wss://localhost/api/v1/ws/server");
+
+ act(() => {
+ socket.open();
+ });
+ expect(screen.getByText("connected")).toBeInTheDocument();
+
+ act(() => {
+ socket.message("first");
+ socket.message("second");
+ });
+
+ expect(screen.getByText("second")).toBeInTheDocument();
+ expect(screen.getByText("2")).toBeInTheDocument();
+ });
+
+ it("keeps only the latest thirty websocket messages", () => {
+ renderWebSocketProvider();
+ const socket = FakeWebSocket.instances[0];
+
+ act(() => {
+ socket.open();
+ for (let index = 0; index < 31; index += 1) {
+ socket.message(`message-${index}`);
+ }
+ });
+
+ expect(screen.getByText("message-30")).toBeInTheDocument();
+ expect(screen.getByText("30")).toBeInTheDocument();
+ });
+
+ it("exposes manual reconnect state separately from socket state", async () => {
+ const user = userEvent.setup();
+ renderWebSocketProvider();
+
+ expect(screen.getByText("stable")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "mark" }));
+ expect(screen.getByText("needs-reconnect")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/fixtures.ts b/src/test/fixtures.ts
new file mode 100644
index 0000000..ca5e125
--- /dev/null
+++ b/src/test/fixtures.ts
@@ -0,0 +1,77 @@
+import type { NezhaServer } from "@/types/nezha-api";
+
+type NezhaServerOverrides = Omit, "host" | "state"> & {
+ host?: Partial;
+ state?: Partial;
+};
+
+const baseHost: NezhaServer["host"] = {
+ platform: "linux",
+ platform_version: "6.8",
+ cpu: ["AMD EPYC"],
+ gpu: [],
+ mem_total: 200,
+ disk_total: 400,
+ swap_total: 100,
+ arch: "amd64",
+ boot_time: 1_735_603_200,
+ version: "1.0.0",
+};
+
+const baseState: NezhaServer["state"] = {
+ cpu: 12,
+ mem_used: 50,
+ swap_used: 10,
+ disk_used: 100,
+ net_in_transfer: 1024 ** 3,
+ net_out_transfer: 2 * 1024 ** 3,
+ net_in_speed: 1024 ** 2,
+ net_out_speed: 2 * 1024 ** 2,
+ uptime: 86_400,
+ load_1: 0.12,
+ load_5: 0.45,
+ load_15: 0.78,
+ tcp_conn_count: 8,
+ udp_conn_count: 4,
+ process_count: 88,
+ temperatures: [],
+ gpu: [],
+};
+
+export function createServer(
+ overrides: NezhaServerOverrides = {},
+): NezhaServer {
+ return {
+ id: 1,
+ name: "edge-1",
+ public_note: "",
+ last_active: "2025-01-01T00:00:00.000Z",
+ country_code: "us",
+ ...overrides,
+ host: {
+ ...baseHost,
+ ...overrides.host,
+ },
+ state: {
+ ...baseState,
+ ...overrides.state,
+ },
+ };
+}
+
+export function createSettingResponse() {
+ return {
+ success: true,
+ data: {
+ config: {
+ debug: false,
+ language: "en-US",
+ site_name: "Nezha",
+ user_template: "",
+ admin_template: "",
+ custom_code: "",
+ },
+ version: "1.0.0",
+ },
+ };
+}
diff --git a/src/test/hooks/hooks.test.tsx b/src/test/hooks/hooks.test.tsx
new file mode 100644
index 0000000..60f9627
--- /dev/null
+++ b/src/test/hooks/hooks.test.tsx
@@ -0,0 +1,129 @@
+import { act, render, renderHook, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { describe, expect, it, vi } from "vitest";
+
+import { useActiveIndicator } from "@/hooks/use-active-indicator";
+import { useBackground } from "@/hooks/use-background";
+import { useChartHistory } from "@/hooks/use-chart-history";
+
+function BackgroundProbe() {
+ const { backgroundImage, updateBackground } = useBackground();
+
+ return (
+
+
{backgroundImage ?? "empty"}
+
+
+
+ );
+}
+
+function ActiveIndicatorProbe({
+ active,
+ items,
+}: {
+ active: string;
+ items: string[];
+}) {
+ const { containerRef, enableIndicatorAnimation, indicator, setItemRef } =
+ useActiveIndicator(items, active);
+
+ return (
+
+
+ {items.map((item, index) => (
+
+ {item}
+
+ ))}
+
+
+ {indicator ? `${indicator.width}:${indicator.shouldAnimate}` : "none"}
+
+
+ );
+}
+
+describe("useBackground", () => {
+ it("updates the global background image and broadcasts changes", async () => {
+ const user = userEvent.setup();
+ render();
+
+ expect(screen.getByText("empty")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "set" }));
+ expect(window.CustomBackgroundImage).toBe("/bg.png");
+ expect(screen.getByText("/bg.png")).toBeInTheDocument();
+
+ await user.click(screen.getByRole("button", { name: "clear" }));
+ expect(screen.getByText("empty")).toBeInTheDocument();
+ });
+
+ it("restores a saved background image during polling", async () => {
+ vi.useFakeTimers();
+ sessionStorage.setItem("savedBackgroundImage", "/saved.png");
+ render();
+
+ act(() => {
+ vi.advanceTimersByTime(100);
+ });
+
+ expect(screen.getByText("/saved.png")).toBeInTheDocument();
+ });
+});
+
+describe("useChartHistory", () => {
+ it("formats websocket message history once and keeps newest data last", () => {
+ const history = [
+ { data: JSON.stringify({ now: 2, servers: [{ id: 1 }] }) },
+ { data: JSON.stringify({ now: 1, servers: [{ id: 1 }] }) },
+ ];
+ const formatFn = vi.fn((wsData: { now: number }, serverId: number) =>
+ serverId === 1 ? wsData.now : null,
+ );
+
+ const { result, rerender } = renderHook(
+ ({ messages }) => useChartHistory(messages, 1, formatFn),
+ { initialProps: { messages: history } },
+ );
+
+ expect(result.current).toEqual([1, 2]);
+ expect(formatFn).toHaveBeenCalledTimes(2);
+
+ rerender({ messages: [...history, { data: JSON.stringify({ now: 3 }) }] });
+ expect(result.current).toEqual([1, 2]);
+ });
+});
+
+describe("useActiveIndicator", () => {
+ it("tracks the active item and clears when it is not available", async () => {
+ Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
+ configurable: true,
+ get() {
+ return 20;
+ },
+ });
+ Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
+ configurable: true,
+ get() {
+ return 10;
+ },
+ });
+
+ const { rerender } = render(
+ ,
+ );
+
+ expect(screen.getByText("20:false")).toBeInTheDocument();
+ rerender();
+ expect(screen.getByText("none")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/lib/format.test.ts b/src/test/lib/format.test.ts
new file mode 100644
index 0000000..3b06c6a
--- /dev/null
+++ b/src/test/lib/format.test.ts
@@ -0,0 +1,21 @@
+import { describe, expect, it } from "vitest";
+
+import { formatBytes } from "@/lib/format";
+
+describe("formatBytes", () => {
+ it("formats empty byte values as zero KiB", () => {
+ expect(formatBytes(0)).toBe("0 KiB");
+ expect(formatBytes(Number.NaN)).toBe("0 KiB");
+ });
+
+ it("keeps byte values in binary units", () => {
+ expect(formatBytes(512)).toBe("0.50 KiB");
+ expect(formatBytes(1024)).toBe("1.00 KiB");
+ expect(formatBytes(1024 ** 2)).toBe("1.00 MiB");
+ expect(formatBytes(1024 ** 3 * 2.5, 1)).toBe("2.5 GiB");
+ });
+
+ it("clamps negative decimal precision to an integer", () => {
+ expect(formatBytes(1536, -1)).toBe("2 KiB");
+ });
+});
diff --git a/src/test/lib/inject.test.ts b/src/test/lib/inject.test.ts
new file mode 100644
index 0000000..f59fec7
--- /dev/null
+++ b/src/test/lib/inject.test.ts
@@ -0,0 +1,64 @@
+import { describe, expect, it, vi } from "vitest";
+
+import { InjectContext } from "@/lib/inject";
+
+describe("InjectContext", () => {
+ it("injects supported resource nodes and marks them for cleanup", async () => {
+ vi.spyOn(console, "log").mockImplementation(() => undefined);
+
+ await InjectContext(`
+
+
+
+ custom content
+ plain text
+ `);
+
+ expect(document.querySelector('meta[name="x-test"]')).toHaveAttribute(
+ "data-injected",
+ "true",
+ );
+ expect(document.querySelector("style[data-injected]")).toHaveTextContent(
+ ".custom",
+ );
+ expect(document.querySelector("script[data-injected]")).toHaveTextContent(
+ "window.__injected = true;",
+ );
+ expect(document.querySelector("#custom-node")).toHaveAttribute(
+ "data-injected",
+ "true",
+ );
+ expect(document.body).toHaveTextContent("plain text");
+ });
+
+ it("cleans previous injected resources before applying new content", async () => {
+ vi.spyOn(console, "log").mockImplementation(() => undefined);
+
+ await InjectContext(`first
`);
+ await InjectContext(`second
`);
+
+ expect(document.querySelector("#first")).not.toBeInTheDocument();
+ expect(document.querySelector("#second")).toBeInTheDocument();
+ });
+
+ it("logs external resource failures without throwing to callers", async () => {
+ vi.spyOn(console, "error").mockImplementation(() => undefined);
+
+ const appendChild = vi
+ .spyOn(document.head, "appendChild")
+ .mockImplementation((node) => {
+ if (node instanceof HTMLScriptElement) {
+ setTimeout(() => node.onerror?.(new Event("error")), 0);
+ }
+ return node;
+ });
+
+ await InjectContext(``);
+
+ expect(appendChild).toHaveBeenCalled();
+ expect(console.error).toHaveBeenCalledWith(
+ "Error during resource injection:",
+ expect.any(Error),
+ );
+ });
+});
diff --git a/src/test/lib/logo-class.test.tsx b/src/test/lib/logo-class.test.tsx
new file mode 100644
index 0000000..38d3129
--- /dev/null
+++ b/src/test/lib/logo-class.test.tsx
@@ -0,0 +1,39 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+
+import {
+ GetFontLogoClass,
+ GetOsName,
+ MageMicrosoftWindows,
+} from "@/lib/logo-class";
+
+describe("logo-class helpers", () => {
+ it("maps known platform aliases to font logo classes", () => {
+ expect(GetFontLogoClass("ubuntu")).toBe("ubuntu");
+ expect(GetFontLogoClass("darwin")).toBe("apple");
+ expect(GetFontLogoClass("linux")).toBe("tux");
+ expect(GetFontLogoClass("amazon")).toBe("redhat");
+ expect(GetFontLogoClass("arch")).toBe("archlinux");
+ expect(GetFontLogoClass("opensuse-tumbleweed")).toBe("opensuse");
+ expect(GetFontLogoClass("unknown")).toBe("tux");
+ });
+
+ it("maps platform aliases to readable operating system names", () => {
+ expect(GetOsName("ubuntu")).toBe("Ubuntu");
+ expect(GetOsName("darwin")).toBe("macOS");
+ expect(GetOsName("linux")).toBe("Linux");
+ expect(GetOsName("amazon")).toBe("Redhat");
+ expect(GetOsName("arch")).toBe("Archlinux");
+ expect(GetOsName("opensuse-tumbleweed")).toBe("Opensuse");
+ expect(GetOsName("unknown")).toBe("Linux");
+ });
+
+ it("renders the Windows SVG icon", () => {
+ render();
+
+ expect(screen.getByTestId("windows-icon")).toHaveAttribute(
+ "viewBox",
+ "0 0 24 24",
+ );
+ });
+});
diff --git a/src/test/lib/nezha-api.test.ts b/src/test/lib/nezha-api.test.ts
new file mode 100644
index 0000000..dc1a069
--- /dev/null
+++ b/src/test/lib/nezha-api.test.ts
@@ -0,0 +1,107 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+
+import {
+ fetchLoginUser,
+ fetchMonitor,
+ fetchServerMetrics,
+ fetchService,
+ fetchSetting,
+} from "@/lib/nezha-api";
+
+const jsonResponse = (body: unknown, init?: ResponseInit) =>
+ new Response(JSON.stringify(body), {
+ status: init?.status ?? 200,
+ statusText: init?.statusText,
+ headers: {
+ "Content-Type": "application/json",
+ ...init?.headers,
+ },
+ });
+
+describe("nezha api fetchers", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ it("returns setting payloads", async () => {
+ const payload = {
+ success: true,
+ data: {
+ config: {
+ debug: false,
+ language: "en-US",
+ site_name: "Nezha",
+ user_template: "",
+ admin_template: "",
+ custom_code: "",
+ },
+ version: "1.0.0",
+ },
+ };
+ vi.mocked(fetch).mockResolvedValueOnce(jsonResponse(payload));
+
+ await expect(fetchSetting()).resolves.toEqual(payload);
+ expect(fetch).toHaveBeenCalledWith("/api/v1/setting");
+ });
+
+ it("throws API error messages returned by service endpoints", async () => {
+ vi.mocked(fetch).mockResolvedValueOnce(
+ jsonResponse({ error: "service unavailable" }),
+ );
+
+ await expect(fetchService()).rejects.toThrow("service unavailable");
+ });
+
+ it("adds monitor and metrics query parameters when periods are provided", async () => {
+ vi.mocked(fetch)
+ .mockResolvedValueOnce(jsonResponse({ success: true, data: [] }))
+ .mockResolvedValueOnce(
+ jsonResponse({
+ success: true,
+ data: {
+ server_id: 7,
+ server_name: "edge",
+ metric: "cpu",
+ data_points: [],
+ },
+ }),
+ );
+
+ await fetchMonitor(7, "7d");
+ await fetchServerMetrics(7, "cpu", "30d");
+
+ expect(fetch).toHaveBeenNthCalledWith(
+ 1,
+ "/api/v1/server/7/service?period=7d",
+ );
+ expect(fetch).toHaveBeenNthCalledWith(
+ 2,
+ "/api/v1/server/7/metrics?metric=cpu&period=30d",
+ );
+ });
+
+ it("refreshes the token when a logged-in browser session has cookies", async () => {
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "nezha_token=token",
+ });
+ const payload = {
+ success: true,
+ data: {
+ id: 1,
+ username: "admin",
+ password: "",
+ created_at: "2025-01-01T00:00:00Z",
+ updated_at: "2025-01-01T00:00:00Z",
+ },
+ };
+ vi.mocked(fetch)
+ .mockResolvedValueOnce(jsonResponse(payload))
+ .mockResolvedValueOnce(jsonResponse({ success: true }));
+
+ await expect(fetchLoginUser()).resolves.toEqual(payload);
+
+ expect(fetch).toHaveBeenNthCalledWith(1, "/api/v1/profile");
+ expect(fetch).toHaveBeenNthCalledWith(2, "/api/v1/refresh-token");
+ });
+});
diff --git a/src/test/lib/static-data.test.ts b/src/test/lib/static-data.test.ts
new file mode 100644
index 0000000..5bfd495
--- /dev/null
+++ b/src/test/lib/static-data.test.ts
@@ -0,0 +1,25 @@
+import { describe, expect, it } from "vitest";
+
+import { geoJsonString } from "@/lib/geo-json-string";
+import { countryCoordinates } from "@/lib/geo-limit";
+
+describe("static geographic data", () => {
+ it("provides known country coordinate metadata", () => {
+ expect(countryCoordinates.CN).toMatchObject({
+ lat: 35,
+ lng: 105,
+ name: "China",
+ });
+ expect(countryCoordinates.US.name).toBe("United States");
+ });
+
+ it("ships parseable GeoJSON feature collection data", () => {
+ const geoJson = JSON.parse(geoJsonString) as {
+ type: string;
+ features: unknown[];
+ };
+
+ expect(geoJson.type).toBe("FeatureCollection");
+ expect(geoJson.features.length).toBeGreaterThan(0);
+ });
+});
diff --git a/src/test/lib/utils.test.ts b/src/test/lib/utils.test.ts
new file mode 100644
index 0000000..c31e07c
--- /dev/null
+++ b/src/test/lib/utils.test.ts
@@ -0,0 +1,346 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import {
+ fetcher,
+ formatNezhaInfo,
+ formatRelativeTime,
+ formatTime,
+ getDaysBetweenDates,
+ getDaysBetweenDatesWithAutoRenewal,
+ getNextCycleTime,
+ handlePublicNote,
+ nezhaFetcher,
+ parsePublicNote,
+} from "@/lib/utils";
+import type { NezhaServer } from "@/types/nezha-api";
+
+const serverFixture: NezhaServer = {
+ id: 1,
+ name: "edge",
+ public_note: '{"planDataMod":{"bandwidth":"1Gbps"}}',
+ last_active: "2025-01-01T00:00:00.000Z",
+ country_code: "US",
+ host: {
+ platform: "linux",
+ platform_version: "6.8",
+ cpu: ["AMD EPYC"],
+ gpu: [],
+ mem_total: 200,
+ disk_total: 400,
+ swap_total: 100,
+ arch: "amd64",
+ boot_time: 1_735_603_200,
+ version: "1.0.0",
+ },
+ state: {
+ cpu: 12,
+ mem_used: 50,
+ swap_used: 10,
+ disk_used: 100,
+ net_in_transfer: 1024,
+ net_out_transfer: 2048,
+ net_in_speed: 1024 * 1024,
+ net_out_speed: 2 * 1024 * 1024,
+ uptime: 3600,
+ load_1: 0.123,
+ load_5: 0.456,
+ load_15: 0.789,
+ tcp_conn_count: 8,
+ udp_conn_count: 4,
+ process_count: 88,
+ temperatures: [],
+ gpu: [],
+ },
+};
+
+describe("date and billing helpers", () => {
+ beforeEach(() => {
+ vi.useFakeTimers();
+ vi.setSystemTime(new Date("2025-01-15T00:00:00.000Z"));
+ });
+
+ it("calculates the next renewal cycle after the specified date", () => {
+ const nextCycle = getNextCycleTime(
+ Date.UTC(2025, 0, 1),
+ 1,
+ Date.UTC(2025, 2, 15),
+ );
+
+ expect(new Date(nextCycle).toISOString()).toBe("2025-04-01T00:00:00.000Z");
+ });
+
+ it("normalizes common cycle labels and remaining package days", () => {
+ const result = getDaysBetweenDatesWithAutoRenewal({
+ startDate: "2025-01-01T00:00:00.000Z",
+ endDate: "2025-01-31T00:00:00.000Z",
+ autoRenewal: "0",
+ cycle: "monthly",
+ amount: "10",
+ });
+
+ expect(result.days).toBe(16);
+ expect(result.cycleLabel).toBe("月");
+ expect(result.remainingPercentage).toBeCloseTo(16 / 30);
+ });
+
+ it("handles auto-renewal before and after the current cycle end", () => {
+ expect(
+ getDaysBetweenDatesWithAutoRenewal({
+ startDate: "2025-01-01T00:00:00.000Z",
+ endDate: "2025-02-01T00:00:00.000Z",
+ autoRenewal: "1",
+ cycle: "quarterly",
+ amount: "10",
+ }),
+ ).toMatchObject({
+ days: 17,
+ cycleLabel: "季",
+ });
+
+ const renewed = getDaysBetweenDatesWithAutoRenewal({
+ startDate: "2024-01-01T00:00:00.000Z",
+ endDate: "2024-12-01T00:00:00.000Z",
+ autoRenewal: "1",
+ cycle: "annual",
+ amount: "10",
+ });
+
+ expect(renewed.days).toBeGreaterThan(300);
+ expect(renewed.cycleLabel).toBe("年");
+ expect(renewed.remainingPercentage).toBeLessThanOrEqual(1);
+ });
+
+ it("rejects invalid cycle calculations", () => {
+ expect(() => getNextCycleTime(Date.UTC(2025, 0, 1), 0, Date.now())).toThrow(
+ "参数无效",
+ );
+ });
+
+ it("formats absolute dates and day differences", () => {
+ expect(formatTime(new Date(2025, 0, 2, 3, 4, 5).getTime())).toBe(
+ "2025-1-2 03:04:05",
+ );
+ expect(getDaysBetweenDates("2025-01-20", "2025-01-15")).toBe(5);
+ });
+
+ it("formats relative timestamps using compact units", () => {
+ expect(formatRelativeTime(Date.now() - 45 * 1000)).toBe("45s");
+ expect(formatRelativeTime(Date.now() - 5 * 60 * 1000)).toBe("5m");
+ expect(formatRelativeTime(Date.now() - 2 * 60 * 60 * 1000)).toBe("2h");
+ expect(formatRelativeTime(Date.now() - 3 * 24 * 60 * 60 * 1000)).toBe("3d");
+ });
+});
+
+describe("public note helpers", () => {
+ it("parses supported public note blocks and defaults missing strings", () => {
+ expect(
+ parsePublicNote(
+ JSON.stringify({
+ billingDataMod: {
+ endDate: "2025-12-31",
+ cycle: "year",
+ },
+ planDataMod: {
+ bandwidth: "1Gbps",
+ IPv4: "1",
+ },
+ }),
+ ),
+ ).toEqual({
+ billingDataMod: {
+ startDate: "",
+ endDate: "2025-12-31",
+ autoRenewal: "",
+ cycle: "year",
+ amount: "",
+ },
+ planDataMod: {
+ bandwidth: "1Gbps",
+ trafficVol: "",
+ trafficType: "",
+ IPv4: "1",
+ IPv6: "",
+ networkRoute: "",
+ extra: "",
+ },
+ });
+ });
+
+ it("returns null for invalid public note JSON", () => {
+ vi.spyOn(console, "error").mockImplementation(() => undefined);
+
+ expect(parsePublicNote("{bad json")).toBeNull();
+ });
+
+ it("returns null or partial blocks for empty and single-section public notes", () => {
+ expect(parsePublicNote("")).toBeNull();
+ expect(parsePublicNote(JSON.stringify({ note: "plain" }))).toBeNull();
+ expect(
+ parsePublicNote(
+ JSON.stringify({
+ billingDataMod: {
+ endDate: "2025-12-31",
+ amount: "20",
+ },
+ }),
+ ),
+ ).toEqual({
+ billingDataMod: {
+ startDate: "",
+ endDate: "2025-12-31",
+ autoRenewal: "",
+ cycle: "",
+ amount: "20",
+ },
+ });
+ expect(
+ parsePublicNote(
+ JSON.stringify({
+ planDataMod: {
+ trafficVol: "1TB",
+ extra: "Backup",
+ },
+ }),
+ ),
+ ).toEqual({
+ planDataMod: {
+ bandwidth: "",
+ trafficVol: "1TB",
+ trafficType: "",
+ IPv4: "",
+ IPv6: "",
+ networkRoute: "",
+ extra: "Backup",
+ },
+ });
+ });
+
+ it("falls back to cached notes when websocket payloads are empty", () => {
+ expect(handlePublicNote(1, "live note")).toBe("live note");
+ expect(handlePublicNote(1, "")).toBe("live note");
+ expect(sessionStorage.getItem("server_1_public_note")).toBe("live note");
+ });
+
+ it("returns an empty public note when no live or cached note exists", () => {
+ expect(handlePublicNote(404, "")).toBe("");
+ });
+});
+
+describe("nezha data formatting", () => {
+ it("maps websocket server state into view-friendly metrics", () => {
+ const now = new Date("2025-01-01T00:00:20.000Z").getTime();
+
+ const result = formatNezhaInfo(now, serverFixture);
+
+ expect(result.online).toBe(true);
+ expect(result.up).toBe(2);
+ expect(result.down).toBe(1);
+ expect(result.mem).toBe(25);
+ expect(result.swap).toBe(10);
+ expect(result.disk).toBe(25);
+ expect(result.load_1).toBe("0.12");
+ expect(result.public_note).toBe(serverFixture.public_note);
+ });
+
+ it("falls back safely for offline timestamps and empty host totals", () => {
+ const result = formatNezhaInfo(Date.now(), {
+ ...serverFixture,
+ public_note: "",
+ last_active: "0001-01-01T00:00:00.000Z",
+ host: {
+ ...serverFixture.host,
+ boot_time: 0,
+ mem_total: 0,
+ swap_total: 0,
+ disk_total: 0,
+ version: "",
+ cpu: [],
+ },
+ state: {
+ ...serverFixture.state,
+ cpu: 0,
+ mem_used: 0,
+ swap_used: 0,
+ disk_used: 0,
+ net_in_speed: 0,
+ net_out_speed: 0,
+ process_count: 0,
+ },
+ });
+
+ expect(result.online).toBe(false);
+ expect(result.last_active_time_string).toBe("");
+ expect(result.boot_time_string).toBe("");
+ expect(result.version).toBeNull();
+ expect(result.mem).toBe(0);
+ expect(result.swap).toBe(0);
+ expect(result.disk).toBe(0);
+ expect(result.public_note).toBe("");
+ });
+});
+
+describe("fetcher", () => {
+ it("returns nested data for successful responses", async () => {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn().mockResolvedValue(
+ new Response(JSON.stringify({ data: { ok: true } }), {
+ headers: { "Content-Type": "application/json" },
+ }),
+ ),
+ );
+
+ await expect(fetcher("/api/v1/demo")).resolves.toEqual({ ok: true });
+ });
+
+ it("logs and rethrows failed responses", async () => {
+ vi.spyOn(console, "error").mockImplementation(() => undefined);
+ vi.stubGlobal(
+ "fetch",
+ vi.fn().mockResolvedValue(
+ new Response(JSON.stringify({ error: "bad" }), {
+ status: 500,
+ statusText: "Server Error",
+ headers: { "Content-Type": "application/json" },
+ }),
+ ),
+ );
+
+ await expect(fetcher("/api/v1/demo")).rejects.toThrow("Server Error");
+ expect(console.error).toHaveBeenCalled();
+ });
+});
+
+describe("nezhaFetcher", () => {
+ it("returns JSON for successful responses", async () => {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn().mockResolvedValue(
+ new Response(JSON.stringify({ success: true }), {
+ headers: { "Content-Type": "application/json" },
+ }),
+ ),
+ );
+
+ await expect(nezhaFetcher("/api/v1/setting")).resolves.toEqual({
+ success: true,
+ });
+ });
+
+ it("throws status and response info for failed responses", async () => {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn().mockResolvedValue(
+ new Response(JSON.stringify({ error: "forbidden" }), {
+ status: 403,
+ statusText: "Forbidden",
+ headers: { "Content-Type": "application/json" },
+ }),
+ ),
+ );
+
+ await expect(nezhaFetcher("/api/v1/setting")).rejects.toMatchObject({
+ status: 403,
+ info: { error: "forbidden" },
+ });
+ });
+});
diff --git a/src/test/pages/Server.test.tsx b/src/test/pages/Server.test.tsx
new file mode 100644
index 0000000..bad679e
--- /dev/null
+++ b/src/test/pages/Server.test.tsx
@@ -0,0 +1,382 @@
+import { screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import { SortProvider } from "@/context/sort-provider";
+import { StatusProvider } from "@/context/status-provider";
+import type { WebSocketContextType } from "@/context/websocket-context";
+import { WebSocketContext } from "@/context/websocket-context";
+import { useStatus } from "@/hooks/use-status";
+import Servers from "@/pages/Server";
+import { createServer } from "@/test/fixtures";
+import { renderWithProviders } from "@/test/utils";
+import type { NezhaServer } from "@/types/nezha-api";
+
+const apiMocks = vi.hoisted(() => ({
+ fetchServerGroup: vi.fn(),
+ fetchService: vi.fn(),
+}));
+
+vi.mock("@/lib/nezha-api", () => apiMocks);
+
+vi.mock("@/components/GlobalMap", () => ({
+ default: ({ serverList }: { serverList: NezhaServer[] }) => (
+ {serverList.length}
+ ),
+}));
+
+vi.mock("@/components/GroupSwitch", () => ({
+ default: ({
+ tabs,
+ setCurrentTab,
+ }: {
+ tabs: string[];
+ setCurrentTab: (tab: string) => void;
+ }) => (
+
+ {tabs.map((tab) => (
+
+ ))}
+
+ ),
+}));
+
+vi.mock("@/components/ServerOverview", () => ({
+ default: ({
+ offline,
+ online,
+ total,
+ }: {
+ offline: number;
+ online: number;
+ total: number;
+ }) => (
+ {`${total}:${online}:${offline}`}
+ ),
+}));
+
+vi.mock("@/components/ServerCard", () => ({
+ default: ({ serverInfo }: { serverInfo: NezhaServer }) => (
+ {serverInfo.name}
+ ),
+}));
+
+vi.mock("@/components/ServerCardInline", () => ({
+ default: ({ serverInfo }: { serverInfo: NezhaServer }) => (
+ {serverInfo.name}
+ ),
+}));
+
+vi.mock("@/components/ServiceTracker", () => ({
+ ServiceTracker: ({ serverList }: { serverList: NezhaServer[] }) => (
+ {serverList.length}
+ ),
+}));
+
+function StatusControl() {
+ const { setStatus } = useStatus();
+
+ return (
+
+ );
+}
+
+function renderServerPage(
+ websocketValue: Partial,
+ { withStatusControl = false } = {},
+) {
+ const defaultWebsocketValue: WebSocketContextType = {
+ lastMessage: null,
+ connected: false,
+ messageHistory: [],
+ reconnect: vi.fn(),
+ needReconnect: false,
+ setNeedReconnect: vi.fn(),
+ };
+
+ return renderWithProviders(
+
+
+
+ {withStatusControl && }
+
+
+
+ ,
+ );
+}
+
+function websocketPayload(servers: NezhaServer[]) {
+ return {
+ data: JSON.stringify({
+ now: Date.parse("2025-01-01T00:00:20.000Z"),
+ servers,
+ }),
+ };
+}
+
+describe("Servers page", () => {
+ beforeEach(() => {
+ apiMocks.fetchServerGroup.mockResolvedValue({
+ success: true,
+ data: [
+ {
+ group: {
+ id: 1,
+ created_at: "",
+ updated_at: "",
+ name: "Edge",
+ },
+ servers: [2],
+ },
+ ],
+ });
+ apiMocks.fetchService.mockResolvedValue({
+ success: true,
+ data: {
+ services: {},
+ cycle_transfer_stats: {},
+ },
+ });
+ });
+
+ it("renders websocket loading and processing states", () => {
+ const { rerender } = renderServerPage({
+ connected: false,
+ lastMessage: null,
+ });
+
+ expect(screen.getByText("info.websocketConnecting")).toBeInTheDocument();
+
+ rerender(
+
+
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByText("info.processing")).toBeInTheDocument();
+ });
+
+ it("summarizes online and offline servers from websocket data", async () => {
+ const online = createServer({ id: 1, name: "alpha" });
+ const offline = createServer({
+ id: 2,
+ name: "beta",
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+
+ renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([online, offline]),
+ });
+
+ expect(screen.getByTestId("server-overview")).toHaveTextContent("2:1:1");
+ expect(screen.getAllByTestId("server-card")).toHaveLength(2);
+ expect(screen.getByText("alpha")).toBeInTheDocument();
+ expect(screen.getByText("beta")).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(apiMocks.fetchServerGroup).toHaveBeenCalled();
+ expect(apiMocks.fetchService).toHaveBeenCalled();
+ });
+ });
+
+ it("filters servers by selected group", async () => {
+ const online = createServer({ id: 1, name: "alpha" });
+ const offline = createServer({
+ id: 2,
+ name: "beta",
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+ const user = userEvent.setup();
+
+ renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([online, offline]),
+ });
+
+ await user.click(await screen.findByTestId("group-Edge"));
+
+ expect(screen.queryByText("alpha")).not.toBeInTheDocument();
+ expect(screen.getByText("beta")).toBeInTheDocument();
+ expect(sessionStorage.getItem("selectedGroup")).toBe("Edge");
+ });
+
+ it("sorts server cards by selected metrics and direction", async () => {
+ const lowCpu = createServer({
+ id: 1,
+ name: "alpha",
+ state: { cpu: 10 },
+ });
+ const highCpu = createServer({
+ id: 2,
+ name: "beta",
+ state: { cpu: 90 },
+ });
+ const user = userEvent.setup();
+
+ renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([lowCpu, highCpu]),
+ });
+
+ await user.selectOptions(screen.getByLabelText("Sort metric"), "cpu");
+ expect(screen.getAllByTestId("server-card")[0]).toHaveTextContent("beta");
+
+ await user.click(screen.getByLabelText("Toggle sort direction"));
+ expect(screen.getAllByTestId("server-card")[0]).toHaveTextContent("alpha");
+ });
+
+ it("keeps name sorting independent from online status", async () => {
+ const onlineAlpha = createServer({
+ id: 1,
+ name: "alpha",
+ });
+ const offlineZeta = createServer({
+ id: 2,
+ name: "zeta",
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+ const user = userEvent.setup();
+
+ renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([onlineAlpha, offlineZeta]),
+ });
+
+ expect(screen.getByLabelText("Toggle sort direction")).toBeDisabled();
+
+ await user.selectOptions(screen.getByLabelText("Sort metric"), "name");
+
+ expect(screen.getAllByTestId("server-card")[0]).toHaveTextContent("zeta");
+
+ await user.click(screen.getByLabelText("Toggle sort direction"));
+ expect(screen.getAllByTestId("server-card")[0]).toHaveTextContent("alpha");
+ });
+
+ it("toggles map and service tracker controls when service data exists", async () => {
+ apiMocks.fetchService.mockResolvedValue({
+ success: true,
+ data: {
+ services: {
+ http: {
+ service_name: "HTTP",
+ current_up: 1,
+ current_down: 0,
+ total_up: 1,
+ total_down: 0,
+ delay: [10],
+ up: [1],
+ down: [0],
+ },
+ },
+ cycle_transfer_stats: {},
+ },
+ });
+ const user = userEvent.setup();
+ const online = createServer({ id: 1, name: "alpha" });
+ const offline = createServer({
+ id: 2,
+ name: "beta",
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+
+ const { container } = renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([online, offline]),
+ });
+
+ await waitFor(() => {
+ expect(apiMocks.fetchService).toHaveBeenCalled();
+ expect(
+ container.querySelectorAll(
+ ".server-overview-controls section > button",
+ ),
+ ).toHaveLength(3);
+ });
+
+ const controls = container.querySelectorAll(
+ ".server-overview-controls section > button",
+ );
+ await user.click(controls[0]);
+ expect(screen.getByTestId("global-map")).toHaveTextContent("2");
+ expect(localStorage.getItem("showMap")).toBe("1");
+
+ await user.click(controls[1]);
+ expect(screen.getByTestId("service-tracker")).toHaveTextContent("2");
+ expect(localStorage.getItem("showServices")).toBe("1");
+ });
+
+ it("does not enable inline cards from storage on mobile widths", () => {
+ localStorage.setItem("inline", "1");
+ Object.defineProperty(window, "innerWidth", {
+ configurable: true,
+ value: 500,
+ });
+ const online = createServer({ id: 1, name: "alpha" });
+
+ renderServerPage({
+ connected: true,
+ lastMessage: websocketPayload([online]),
+ });
+
+ expect(screen.getByTestId("server-card")).toHaveTextContent("alpha");
+ expect(screen.queryByTestId("server-card-inline")).not.toBeInTheDocument();
+ });
+
+ it("applies external status filters and inline card preferences", async () => {
+ localStorage.setItem("inline", "1");
+ Object.defineProperty(window, "innerWidth", {
+ configurable: true,
+ value: 1024,
+ });
+ const online = createServer({ id: 1, name: "alpha" });
+ const offline = createServer({
+ id: 2,
+ name: "beta",
+ last_active: "2024-12-31T23:00:00.000Z",
+ });
+ const user = userEvent.setup();
+
+ renderServerPage(
+ {
+ connected: true,
+ lastMessage: websocketPayload([online, offline]),
+ },
+ { withStatusControl: true },
+ );
+
+ await waitFor(() => {
+ expect(screen.getAllByTestId("server-card-inline")).toHaveLength(2);
+ });
+
+ await user.click(screen.getByRole("button", { name: "online-only" }));
+
+ expect(screen.getAllByTestId("server-card-inline")).toHaveLength(1);
+ expect(screen.getByText("alpha")).toBeInTheDocument();
+ expect(screen.queryByText("beta")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/test/pages/pages.test.tsx b/src/test/pages/pages.test.tsx
new file mode 100644
index 0000000..dcd2b77
--- /dev/null
+++ b/src/test/pages/pages.test.tsx
@@ -0,0 +1,130 @@
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter, Route, Routes, useLocation } from "react-router-dom";
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import ErrorPage from "@/pages/ErrorPage";
+import NotFound from "@/pages/NotFound";
+import ServerDetail from "@/pages/ServerDetail";
+
+vi.mock("@/components/NetworkChart", () => ({
+ NetworkChart: ({ server_id, show }: { server_id: number; show: boolean }) => (
+ {`${server_id}:${show}`}
+ ),
+}));
+
+vi.mock("@/components/ServerDetailChart", () => ({
+ default: ({ server_id }: { server_id: string }) => (
+ {server_id}
+ ),
+}));
+
+vi.mock("@/components/ServerDetailOverview", () => ({
+ default: ({ server_id }: { server_id: string }) => (
+ {server_id}
+ ),
+}));
+
+vi.mock("@/components/TabSwitch", () => ({
+ default: ({
+ tabs,
+ setCurrentTab,
+ }: {
+ tabs: string[];
+ setCurrentTab: (tab: string) => void;
+ }) => (
+
+ {tabs.map((tab) => (
+
+ ))}
+
+ ),
+}));
+
+function LocationProbe() {
+ const location = useLocation();
+ return {location.pathname}
;
+}
+
+describe("simple pages", () => {
+ it("renders explicit and translated error messages", () => {
+ const { rerender } = render();
+
+ expect(screen.getByText("418")).toBeInTheDocument();
+ expect(screen.getByText("short")).toBeInTheDocument();
+
+ rerender();
+ expect(screen.getByText("error.somethingWentWrong")).toBeInTheDocument();
+ });
+
+ it("navigates back home from the not found page", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+
+
+
+ >
+ }
+ />
+
+ home
+
+ >
+ }
+ />
+
+ ,
+ );
+
+ expect(screen.getByText("404")).toBeInTheDocument();
+ await user.click(screen.getByRole("button", { name: "error.backToHome" }));
+ expect(screen.getByText("home")).toBeInTheDocument();
+ expect(screen.getByText("/")).toBeInTheDocument();
+ });
+});
+
+describe("ServerDetail", () => {
+ beforeEach(() => {
+ vi.stubGlobal("scrollTo", vi.fn());
+ });
+
+ it("renders detail tab by default and can switch to network tab", async () => {
+ const user = userEvent.setup();
+ render(
+
+
+ } />
+
+ ,
+ );
+
+ expect(screen.getByTestId("detail-overview")).toHaveTextContent("7");
+ expect(screen.getByTestId("detail-chart")).toHaveTextContent("7");
+ expect(screen.getByTestId("network-chart")).toHaveTextContent("7:false");
+
+ await user.click(screen.getByRole("button", { name: "Network" }));
+ expect(screen.getByTestId("network-chart")).toHaveTextContent("7:true");
+ });
+
+ it("redirects when route params are missing", async () => {
+ render(
+
+
+ } />
+ redirected
} />
+
+ ,
+ );
+
+ expect(await screen.findByText("redirected")).toBeInTheDocument();
+ });
+});
diff --git a/src/test/setup.ts b/src/test/setup.ts
new file mode 100644
index 0000000..43ddc31
--- /dev/null
+++ b/src/test/setup.ts
@@ -0,0 +1,110 @@
+import "@testing-library/jest-dom/vitest";
+import { cleanup } from "@testing-library/react";
+import { afterEach, vi } from "vitest";
+
+vi.mock("react-i18next", () => ({
+ initReactI18next: {
+ type: "3rdParty",
+ init: vi.fn(),
+ },
+ useTranslation: () => ({
+ t: (key: string) => key,
+ i18n: {
+ language: "en-US",
+ languages: ["en-US"],
+ changeLanguage: vi.fn(),
+ },
+ }),
+}));
+
+Object.defineProperty(window, "matchMedia", {
+ writable: true,
+ value: vi.fn().mockImplementation((query: string) => ({
+ matches: false,
+ media: query,
+ onchange: null,
+ addListener: vi.fn(),
+ removeListener: vi.fn(),
+ addEventListener: vi.fn(),
+ removeEventListener: vi.fn(),
+ dispatchEvent: vi.fn(),
+ })),
+});
+
+class ResizeObserverMock {
+ observe = vi.fn();
+ unobserve = vi.fn();
+ disconnect = vi.fn();
+}
+
+class IntersectionObserverMock {
+ readonly root = null;
+ readonly rootMargin = "";
+ readonly thresholds = [];
+
+ observe = vi.fn();
+ unobserve = vi.fn();
+ disconnect = vi.fn();
+ takeRecords = vi.fn(() => []);
+}
+
+Object.defineProperty(globalThis, "ResizeObserver", {
+ writable: true,
+ value: ResizeObserverMock,
+});
+
+Object.defineProperty(globalThis, "IntersectionObserver", {
+ writable: true,
+ value: IntersectionObserverMock,
+});
+
+Object.defineProperty(HTMLElement.prototype, "scrollIntoView", {
+ configurable: true,
+ value: vi.fn(),
+});
+
+Object.defineProperty(HTMLElement.prototype, "hasPointerCapture", {
+ configurable: true,
+ value: vi.fn(() => false),
+});
+
+Object.defineProperty(HTMLElement.prototype, "setPointerCapture", {
+ configurable: true,
+ value: vi.fn(),
+});
+
+Object.defineProperty(HTMLElement.prototype, "releasePointerCapture", {
+ configurable: true,
+ value: vi.fn(),
+});
+
+afterEach(() => {
+ cleanup();
+ localStorage.clear();
+ sessionStorage.clear();
+ document.head
+ .querySelectorAll('meta[name="theme-color"], [data-injected]')
+ .forEach((node) => {
+ node.remove();
+ });
+ document.body.querySelectorAll("[data-injected]").forEach((node) => {
+ node.remove();
+ });
+ document.documentElement.className = "";
+ document.documentElement.removeAttribute("style");
+ Object.defineProperty(document, "cookie", {
+ configurable: true,
+ value: "",
+ });
+ window.CustomBackgroundImage = "";
+ window.CustomMobileBackgroundImage = "";
+ window.ForceShowServices = false;
+ window.ForceCardInline = false;
+ window.ForceShowMap = false;
+ window.ForcePeakCutEnabled = false;
+ window.ForceSortType = undefined;
+ window.ForceSortOrder = undefined;
+ vi.unstubAllGlobals();
+ vi.restoreAllMocks();
+ vi.useRealTimers();
+});
diff --git a/src/test/utils.tsx b/src/test/utils.tsx
new file mode 100644
index 0000000..e2c465b
--- /dev/null
+++ b/src/test/utils.tsx
@@ -0,0 +1,42 @@
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { type RenderOptions, render } from "@testing-library/react";
+import type { ReactElement, ReactNode } from "react";
+import { MemoryRouter } from "react-router-dom";
+
+export function createTestQueryClient() {
+ return new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ gcTime: 0,
+ },
+ },
+ });
+}
+
+type RenderWithProvidersOptions = RenderOptions & {
+ route?: string;
+ queryClient?: QueryClient;
+};
+
+export function renderWithProviders(
+ ui: ReactElement,
+ {
+ route = "/",
+ queryClient = createTestQueryClient(),
+ ...renderOptions
+ }: RenderWithProvidersOptions = {},
+) {
+ function Wrapper({ children }: { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return {
+ queryClient,
+ ...render(ui, { wrapper: Wrapper, ...renderOptions }),
+ };
+}
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 2397ca5..d6337b6 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -14,7 +14,7 @@
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
- "types": ["node"],
+ "types": ["node", "vitest/globals", "@testing-library/jest-dom"],
"paths": {
"@/*": ["./src/*"]
},
diff --git a/vite.config.ts b/vite.config.ts
index f51d39d..02bda37 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import react from "@vitejs/plugin-react";
-import { defineConfig } from "vite";
+import { defineConfig } from "vitest/config";
// Get git commit hash
const getGitHash = () => {
@@ -63,6 +63,39 @@ export default defineConfig({
Pragma: "no-cache",
},
},
+ test: {
+ environment: "jsdom",
+ environmentOptions: {
+ jsdom: {
+ url: "https://localhost/",
+ },
+ },
+ globals: true,
+ setupFiles: ["./src/test/setup.ts"],
+ css: true,
+ include: ["src/test/**/*.{test,spec}.{ts,tsx}"],
+ coverage: {
+ provider: "v8",
+ reporter: ["text", "html", "lcov"],
+ reportsDirectory: "./coverage",
+ thresholds: {
+ statements: 86,
+ branches: 74,
+ functions: 86,
+ lines: 86,
+ },
+ include: ["src/**/*.{ts,tsx}"],
+ exclude: [
+ "src/**/*.test.{ts,tsx}",
+ "src/**/*.spec.{ts,tsx}",
+ "src/test/**",
+ "src/types/**",
+ "src/main.tsx",
+ "src/i18n.js",
+ "src/vite-env.d.ts",
+ ],
+ },
+ },
build: {
rolldownOptions: {
output: {
From f536d4ecf56648549653654069b0732027cda3a4 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Mon, 15 Jun 2026 18:45:29 +0800
Subject: [PATCH 40/64] fix(api): implement CSRF token handling for refresh
token requests
---
src/lib/nezha-api.ts | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/lib/nezha-api.ts b/src/lib/nezha-api.ts
index 02526c2..8e73d03 100644
--- a/src/lib/nezha-api.ts
+++ b/src/lib/nezha-api.ts
@@ -11,6 +11,22 @@ import type {
let lastestRefreshTokenAt = 0;
+const getCookieValue = (name: string): string | undefined => {
+ const cookie = document.cookie
+ .split("; ")
+ .find((item) => item.startsWith(`${name}=`));
+
+ if (!cookie) {
+ return undefined;
+ }
+
+ return decodeURIComponent(cookie.split("=").slice(1).join("="));
+};
+
+const getCsrfToken = (): string => {
+ return getCookieValue("nz-csrf") || "";
+};
+
export const fetchServerGroup = async (): Promise => {
const response = await fetch("/api/v1/server-group");
const data = await response.json();
@@ -34,7 +50,14 @@ export const fetchLoginUser = async (): Promise => {
Date.now() - lastestRefreshTokenAt > 1000 * 60 * 60)
) {
lastestRefreshTokenAt = Date.now();
- fetch("/api/v1/refresh-token");
+ const csrfToken = getCsrfToken();
+ console.log("Refreshing token with CSRF token:", csrfToken);
+ fetch("/api/v1/refresh-token", {
+ method: "POST",
+ headers: {
+ "X-CSRF-Token": csrfToken,
+ },
+ });
}
return data;
From ea19d3cc270952768296df3298123ec1a9adc081 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Mon, 15 Jun 2026 18:46:36 +0800
Subject: [PATCH 41/64] chore(deps): update tailwindcss and postcss to version
4.3.1
---
package.json | 4 +-
pnpm-lock.yaml | 174 ++++++++++++++++++++++++-------------------------
2 files changed, 89 insertions(+), 89 deletions(-)
diff --git a/package.json b/package.json
index 8b82095..3aaf103 100644
--- a/package.json
+++ b/package.json
@@ -64,7 +64,7 @@
},
"devDependencies": {
"@biomejs/biome": "2.4.16",
- "@tailwindcss/postcss": "^4.3.0",
+ "@tailwindcss/postcss": "^4.3.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
@@ -76,7 +76,7 @@
"globals": "17.6.0",
"jsdom": "^29.1.1",
"postcss": "8.5.15",
- "tailwindcss": "^4.3.0",
+ "tailwindcss": "^4.3.1",
"typescript": "~6.0.3",
"vite": "8.0.16",
"vitest": "^4.1.8"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1266251..d1e3284 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -121,14 +121,14 @@ importers:
version: 3.6.0
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@4.3.0)
+ version: 1.0.7(tailwindcss@4.3.1)
devDependencies:
'@biomejs/biome':
specifier: 2.4.16
version: 2.4.16
'@tailwindcss/postcss':
- specifier: ^4.3.0
- version: 4.3.0
+ specifier: ^4.3.1
+ version: 4.3.1
'@testing-library/jest-dom':
specifier: ^6.9.1
version: 6.9.1
@@ -163,8 +163,8 @@ importers:
specifier: 8.5.15
version: 8.5.15
tailwindcss:
- specifier: ^4.3.0
- version: 4.3.0
+ specifier: ^4.3.1
+ version: 4.3.1
typescript:
specifier: ~6.0.3
version: 6.0.3
@@ -300,8 +300,8 @@ packages:
'@csstools/css-parser-algorithms': ^4.0.0
'@csstools/css-tokenizer': ^4.0.0
- '@csstools/css-color-parser@4.1.4':
- resolution: {integrity: sha512-yI8kNhHiOrLb8Rlulsk07DeQz0PwyT69FX9dkz5rAp7p9RUwFKEXnZpBGzURiLHgi66YqIWxOHn1nij8Lrg27Q==}
+ '@csstools/css-color-parser@4.1.5':
+ resolution: {integrity: sha512-u8pwA3YOFaJphdZTJjYhjElnWN7ucO4osu5BiK3sKhOAD5op21VkSBiu5g5NuOB3/tGjSqq7yclSrB+cjLSSKg==}
engines: {node: '>=20.19.0'}
peerDependencies:
'@csstools/css-parser-algorithms': ^4.0.0
@@ -382,8 +382,8 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
- '@napi-rs/wasm-runtime@1.1.4':
- resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
+ '@napi-rs/wasm-runtime@1.1.5':
+ resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==}
peerDependencies:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
@@ -948,69 +948,69 @@ packages:
'@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
- '@tailwindcss/node@4.3.0':
- resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==}
+ '@tailwindcss/node@4.3.1':
+ resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==}
- '@tailwindcss/oxide-android-arm64@4.3.0':
- resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==}
+ '@tailwindcss/oxide-android-arm64@4.3.1':
+ resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [android]
- '@tailwindcss/oxide-darwin-arm64@4.3.0':
- resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==}
+ '@tailwindcss/oxide-darwin-arm64@4.3.1':
+ resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [darwin]
- '@tailwindcss/oxide-darwin-x64@4.3.0':
- resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==}
+ '@tailwindcss/oxide-darwin-x64@4.3.1':
+ resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==}
engines: {node: '>= 20'}
cpu: [x64]
os: [darwin]
- '@tailwindcss/oxide-freebsd-x64@4.3.0':
- resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==}
+ '@tailwindcss/oxide-freebsd-x64@4.3.1':
+ resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==}
engines: {node: '>= 20'}
cpu: [x64]
os: [freebsd]
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0':
- resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==}
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1':
+ resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==}
engines: {node: '>= 20'}
cpu: [arm]
os: [linux]
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.0':
- resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==}
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.1':
+ resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@tailwindcss/oxide-linux-arm64-musl@4.3.0':
- resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==}
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.1':
+ resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@tailwindcss/oxide-linux-x64-gnu@4.3.0':
- resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==}
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.1':
+ resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@tailwindcss/oxide-linux-x64-musl@4.3.0':
- resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==}
+ '@tailwindcss/oxide-linux-x64-musl@4.3.1':
+ resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==}
engines: {node: '>= 20'}
cpu: [x64]
os: [linux]
libc: [musl]
- '@tailwindcss/oxide-wasm32-wasi@4.3.0':
- resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==}
+ '@tailwindcss/oxide-wasm32-wasi@4.3.1':
+ resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
bundledDependencies:
@@ -1021,24 +1021,24 @@ packages:
- '@emnapi/wasi-threads'
- tslib
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.0':
- resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==}
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.1':
+ resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==}
engines: {node: '>= 20'}
cpu: [arm64]
os: [win32]
- '@tailwindcss/oxide-win32-x64-msvc@4.3.0':
- resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==}
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.1':
+ resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==}
engines: {node: '>= 20'}
cpu: [x64]
os: [win32]
- '@tailwindcss/oxide@4.3.0':
- resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==}
+ '@tailwindcss/oxide@4.3.1':
+ resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==}
engines: {node: '>= 20'}
- '@tailwindcss/postcss@4.3.0':
- resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==}
+ '@tailwindcss/postcss@4.3.1':
+ resolution: {integrity: sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==}
'@tanstack/query-core@5.101.0':
resolution: {integrity: sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==}
@@ -1360,8 +1360,8 @@ packages:
dom-accessibility-api@0.6.3:
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
- enhanced-resolve@5.23.0:
- resolution: {integrity: sha512-yJN/BOOLxcOW2aQgeif9mSnaUB8KtvmMMp56oA1kx1CRfBKbhZm2pJ+NBY+3eOboHxix8lfjWpHE0Ei5U8RbSA==}
+ enhanced-resolve@5.21.6:
+ resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==}
engines: {node: '>=10.13.0'}
entities@8.0.0:
@@ -1371,8 +1371,8 @@ packages:
es-module-lexer@2.1.0:
resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==}
- es-toolkit@1.47.0:
- resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==}
+ es-toolkit@1.47.1:
+ resolution: {integrity: sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==}
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -1800,8 +1800,8 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
- tailwindcss@4.3.0:
- resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==}
+ tailwindcss@4.3.1:
+ resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==}
tapable@2.3.3:
resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
@@ -2009,7 +2009,7 @@ snapshots:
dependencies:
'@asamuzakjp/generational-cache': 1.0.1
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
- '@csstools/css-color-parser': 4.1.4(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
+ '@csstools/css-color-parser': 4.1.5(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
'@csstools/css-tokenizer': 4.0.0
@@ -2094,7 +2094,7 @@ snapshots:
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
'@csstools/css-tokenizer': 4.0.0
- '@csstools/css-color-parser@4.1.4(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
+ '@csstools/css-color-parser@4.1.5(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
dependencies:
'@csstools/color-helpers': 6.0.2
'@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
@@ -2171,7 +2171,7 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
- '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
+ '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
dependencies:
'@emnapi/core': 1.10.0
'@emnapi/runtime': 1.10.0
@@ -2682,7 +2682,7 @@ snapshots:
dependencies:
'@emnapi/core': 1.10.0
'@emnapi/runtime': 1.10.0
- '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
+ '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.3':
@@ -2697,74 +2697,74 @@ snapshots:
'@standard-schema/utils@0.3.0': {}
- '@tailwindcss/node@4.3.0':
+ '@tailwindcss/node@4.3.1':
dependencies:
'@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.23.0
+ enhanced-resolve: 5.21.6
jiti: 2.7.0
lightningcss: 1.32.0
magic-string: 0.30.21
source-map-js: 1.2.1
- tailwindcss: 4.3.0
+ tailwindcss: 4.3.1
- '@tailwindcss/oxide-android-arm64@4.3.0':
+ '@tailwindcss/oxide-android-arm64@4.3.1':
optional: true
- '@tailwindcss/oxide-darwin-arm64@4.3.0':
+ '@tailwindcss/oxide-darwin-arm64@4.3.1':
optional: true
- '@tailwindcss/oxide-darwin-x64@4.3.0':
+ '@tailwindcss/oxide-darwin-x64@4.3.1':
optional: true
- '@tailwindcss/oxide-freebsd-x64@4.3.0':
+ '@tailwindcss/oxide-freebsd-x64@4.3.1':
optional: true
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0':
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1':
optional: true
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.0':
+ '@tailwindcss/oxide-linux-arm64-gnu@4.3.1':
optional: true
- '@tailwindcss/oxide-linux-arm64-musl@4.3.0':
+ '@tailwindcss/oxide-linux-arm64-musl@4.3.1':
optional: true
- '@tailwindcss/oxide-linux-x64-gnu@4.3.0':
+ '@tailwindcss/oxide-linux-x64-gnu@4.3.1':
optional: true
- '@tailwindcss/oxide-linux-x64-musl@4.3.0':
+ '@tailwindcss/oxide-linux-x64-musl@4.3.1':
optional: true
- '@tailwindcss/oxide-wasm32-wasi@4.3.0':
+ '@tailwindcss/oxide-wasm32-wasi@4.3.1':
optional: true
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.0':
+ '@tailwindcss/oxide-win32-arm64-msvc@4.3.1':
optional: true
- '@tailwindcss/oxide-win32-x64-msvc@4.3.0':
+ '@tailwindcss/oxide-win32-x64-msvc@4.3.1':
optional: true
- '@tailwindcss/oxide@4.3.0':
+ '@tailwindcss/oxide@4.3.1':
optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.3.0
- '@tailwindcss/oxide-darwin-arm64': 4.3.0
- '@tailwindcss/oxide-darwin-x64': 4.3.0
- '@tailwindcss/oxide-freebsd-x64': 4.3.0
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0
- '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0
- '@tailwindcss/oxide-linux-arm64-musl': 4.3.0
- '@tailwindcss/oxide-linux-x64-gnu': 4.3.0
- '@tailwindcss/oxide-linux-x64-musl': 4.3.0
- '@tailwindcss/oxide-wasm32-wasi': 4.3.0
- '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0
- '@tailwindcss/oxide-win32-x64-msvc': 4.3.0
+ '@tailwindcss/oxide-android-arm64': 4.3.1
+ '@tailwindcss/oxide-darwin-arm64': 4.3.1
+ '@tailwindcss/oxide-darwin-x64': 4.3.1
+ '@tailwindcss/oxide-freebsd-x64': 4.3.1
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1
+ '@tailwindcss/oxide-linux-arm64-musl': 4.3.1
+ '@tailwindcss/oxide-linux-x64-gnu': 4.3.1
+ '@tailwindcss/oxide-linux-x64-musl': 4.3.1
+ '@tailwindcss/oxide-wasm32-wasi': 4.3.1
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1
+ '@tailwindcss/oxide-win32-x64-msvc': 4.3.1
- '@tailwindcss/postcss@4.3.0':
+ '@tailwindcss/postcss@4.3.1':
dependencies:
'@alloc/quick-lru': 5.2.0
- '@tailwindcss/node': 4.3.0
- '@tailwindcss/oxide': 4.3.0
+ '@tailwindcss/node': 4.3.1
+ '@tailwindcss/oxide': 4.3.1
postcss: 8.5.15
- tailwindcss: 4.3.0
+ tailwindcss: 4.3.1
'@tanstack/query-core@5.101.0': {}
@@ -3073,7 +3073,7 @@ snapshots:
dom-accessibility-api@0.6.3: {}
- enhanced-resolve@5.23.0:
+ enhanced-resolve@5.21.6:
dependencies:
graceful-fs: 4.2.11
tapable: 2.3.3
@@ -3082,7 +3082,7 @@ snapshots:
es-module-lexer@2.1.0: {}
- es-toolkit@1.47.0: {}
+ es-toolkit@1.47.1: {}
estree-walker@3.0.3:
dependencies:
@@ -3364,7 +3364,7 @@ snapshots:
'@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1))(react@19.2.7)
clsx: 2.1.1
decimal.js-light: 2.5.1
- es-toolkit: 1.47.0
+ es-toolkit: 1.47.1
eventemitter3: 5.0.4
immer: 10.2.0
react: 19.2.7
@@ -3450,11 +3450,11 @@ snapshots:
tailwind-merge@3.6.0: {}
- tailwindcss-animate@1.0.7(tailwindcss@4.3.0):
+ tailwindcss-animate@1.0.7(tailwindcss@4.3.1):
dependencies:
- tailwindcss: 4.3.0
+ tailwindcss: 4.3.1
- tailwindcss@4.3.0: {}
+ tailwindcss@4.3.1: {}
tapable@2.3.3: {}
From 21d60076ceb04ef7e8ce6d25a5e23a3a3575d4df Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Mon, 15 Jun 2026 18:51:19 +0800
Subject: [PATCH 42/64] fix(api): enhance token refresh handling with CSRF
token support
---
src/test/lib/nezha-api.test.ts | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/test/lib/nezha-api.test.ts b/src/test/lib/nezha-api.test.ts
index dc1a069..7b772a5 100644
--- a/src/test/lib/nezha-api.test.ts
+++ b/src/test/lib/nezha-api.test.ts
@@ -83,7 +83,7 @@ describe("nezha api fetchers", () => {
it("refreshes the token when a logged-in browser session has cookies", async () => {
Object.defineProperty(document, "cookie", {
configurable: true,
- value: "nezha_token=token",
+ value: "nezha_token=token; nz-csrf=test-csrf-token",
});
const payload = {
success: true,
@@ -102,6 +102,11 @@ describe("nezha api fetchers", () => {
await expect(fetchLoginUser()).resolves.toEqual(payload);
expect(fetch).toHaveBeenNthCalledWith(1, "/api/v1/profile");
- expect(fetch).toHaveBeenNthCalledWith(2, "/api/v1/refresh-token");
+ expect(fetch).toHaveBeenNthCalledWith(2, "/api/v1/refresh-token", {
+ method: "POST",
+ headers: {
+ "X-CSRF-Token": "test-csrf-token",
+ },
+ });
});
});
From f2b13da7b16dd0668bc7ec7a6c328a435aa3cbd7 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 19 Jun 2026 23:03:21 +0800
Subject: [PATCH 43/64] chore(deps): bump actions/checkout from 6 to 7 in the
all group (#71)
Bumps the all group with 1 update: [actions/checkout](https://github.com/actions/checkout).
Updates `actions/checkout` from 6 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-version: '7'
dependency-type: direct:production
update-type: version-update:semver-major
dependency-group: all
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/Build.yml | 2 +-
.github/workflows/auto-fix-lint-format-commit.yml | 2 +-
.github/workflows/ci.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml
index 7218006..c338d62 100644
--- a/.github/workflows/Build.yml
+++ b/.github/workflows/Build.yml
@@ -12,7 +12,7 @@ jobs:
contents: write
steps:
- name: Check out code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
with:
fetch-depth: 0
diff --git a/.github/workflows/auto-fix-lint-format-commit.yml b/.github/workflows/auto-fix-lint-format-commit.yml
index cc702d7..dd3d7e4 100644
--- a/.github/workflows/auto-fix-lint-format-commit.yml
+++ b/.github/workflows/auto-fix-lint-format-commit.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
with:
fetch-depth: 0
ref: ${{ github.head_ref }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8e8fd81..e149040 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,7 +18,7 @@ jobs:
contents: read
steps:
- name: Check out code
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Set up pnpm
uses: pnpm/action-setup@v6
From 03977c4b4d86ecb3f760126c9b57edce0a56675c Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sat, 20 Jun 2026 00:06:50 +0800
Subject: [PATCH 44/64] refactor: update websocket context to use structured
data and lazy load components
- Changed websocket context to use `lastData` instead of `lastMessage` for better type safety and clarity.
- Updated components to handle the new websocket data structure, including `DashCommand`, `Header`, `ServerDetail`, and various chart components.
- Introduced lazy loading for `NotFound`, `ServerDetail`, and `NetworkChart` components to improve performance.
- Added skeleton loading states for `ServerDetail` to enhance user experience during data fetching.
- Updated tests to reflect changes in websocket data handling and component structure.
---
src/App.tsx | 48 +++++++++++++++++--
src/components/DashCommand.tsx | 7 +--
src/components/Header.tsx | 8 +---
src/components/ServerDetailChart.tsx | 43 +++++++----------
src/components/ServerDetailSummary.tsx | 9 ++--
src/context/websocket-context.ts | 7 +--
src/context/websocket-provider.tsx | 32 ++++++++-----
src/hooks/use-chart-history.ts | 5 +-
src/main.tsx | 15 +++++-
src/pages/Server.tsx | 10 ++--
src/pages/ServerDetail.tsx | 25 +++++-----
src/test/components/dash-command.test.tsx | 31 ++++++------
src/test/components/header.test.tsx | 12 +++--
.../components/server-detail-chart.test.tsx | 18 ++++---
.../server-detail-components.test.tsx | 23 +++++----
src/test/context/providers.test.tsx | 39 +++++++++++++--
src/test/hooks/hooks.test.tsx | 6 +--
src/test/pages/Server.test.tsx | 26 +++++-----
src/test/pages/pages.test.tsx | 7 ++-
src/types/nezha-api.ts | 1 +
20 files changed, 225 insertions(+), 147 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 02b2a74..4205103 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,6 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import type React from "react";
-import { useEffect, useState } from "react";
+import { lazy, Suspense, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
@@ -8,15 +8,39 @@ import { DashCommand } from "./components/DashCommand";
import ErrorBoundary from "./components/ErrorBoundary";
import Footer from "./components/Footer";
import Header, { RefreshToast } from "./components/Header";
+import { Skeleton } from "./components/ui/skeleton";
import { useBackground } from "./hooks/use-background";
import { useTheme } from "./hooks/use-theme";
import { InjectContext } from "./lib/inject";
import { fetchSetting } from "./lib/nezha-api";
import { cn } from "./lib/utils";
import ErrorPage from "./pages/ErrorPage";
-import NotFound from "./pages/NotFound";
import Server from "./pages/Server";
-import ServerDetail from "./pages/ServerDetail";
+
+const NotFound = lazy(() => import("./pages/NotFound"));
+const ServerDetail = lazy(() => import("./pages/ServerDetail"));
+
+function ServerDetailRouteFallback() {
+ return (
+
+ );
+}
// Route checker component
const RouteChecker: React.FC = () => {
@@ -110,9 +134,23 @@ const MainApp: React.FC = () => {
} />
- } />
+ }>
+
+
+ }
+ />
} />
- } />
+
+
+
+ }
+ />
diff --git a/src/components/DashCommand.tsx b/src/components/DashCommand.tsx
index e913b0f..9981ff2 100644
--- a/src/components/DashCommand.tsx
+++ b/src/components/DashCommand.tsx
@@ -17,7 +17,6 @@ import { useCommand } from "@/hooks/use-command";
import { useTheme } from "@/hooks/use-theme";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
import { formatNezhaInfo } from "@/lib/utils";
-import type { NezhaWebsocketResponse } from "@/types/nezha-api";
export function DashCommand() {
const { isOpen, closeCommand, toggleCommand } = useCommand();
@@ -26,11 +25,9 @@ export function DashCommand() {
const { t } = useTranslation();
const { setTheme } = useTheme();
- const { lastMessage, connected } = useWebSocketContext();
+ const { lastData, connected } = useWebSocketContext();
- const nezhaWsData = lastMessage
- ? (JSON.parse(lastMessage.data) as NezhaWebsocketResponse)
- : null;
+ const nezhaWsData = lastData;
useEffect(() => {
const down = (e: KeyboardEvent) => {
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index b2e7794..d67efbf 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -60,13 +60,9 @@ function Header() {
refetchOnWindowFocus: true,
});
- const { lastMessage, connected } = useWebSocketContext();
+ const { lastData, connected } = useWebSocketContext();
- const onlineCount = connected
- ? lastMessage
- ? JSON.parse(lastMessage.data).online || 0
- : 0
- : "...";
+ const onlineCount = connected ? (lastData ? lastData.online || 0 : 0) : "...";
const siteName = settingData?.data?.config?.site_name;
diff --git a/src/components/ServerDetailChart.tsx b/src/components/ServerDetailChart.tsx
index 21176ff..2a829e4 100644
--- a/src/components/ServerDetailChart.tsx
+++ b/src/components/ServerDetailChart.tsx
@@ -211,7 +211,7 @@ export default function ServerDetailChart({
}: {
server_id: string;
}) {
- const { lastMessage, connected, messageHistory } = useWebSocketContext();
+ const { lastData, connected, messageHistory } = useWebSocketContext();
const [selectedPeriod, setSelectedPeriod] = useState("realtime");
// Check if user is logged in
@@ -256,13 +256,11 @@ export default function ServerDetailChart({
}
}, [isLogin, isTsdbEnabled, selectedPeriod]);
- if (!connected && !lastMessage) {
+ if (!connected && !lastData) {
return ;
}
- const nezhaWsData = lastMessage
- ? (JSON.parse(lastMessage.data) as NezhaWebsocketResponse)
- : null;
+ const nezhaWsData = lastData;
if (!nezhaWsData) {
return ;
@@ -436,7 +434,7 @@ function GpuChart({
index: number;
gpuStat: number;
gpuName?: string;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const [gpuChartData, setGpuChartData] = useState([]);
@@ -467,8 +465,7 @@ function GpuChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === id);
if (!server) return null;
const { gpu } = formatNezhaInfo(wsData.now, server);
@@ -630,7 +627,7 @@ function CpuChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const [cpuChartData, setCpuChartData] = useState([]);
@@ -663,8 +660,7 @@ function CpuChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { cpu } = formatNezhaInfo(wsData.now, server);
@@ -824,7 +820,7 @@ function ProcessChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const { t } = useTranslation();
@@ -865,8 +861,7 @@ function ProcessChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { process } = formatNezhaInfo(wsData.now, server);
@@ -1020,7 +1015,7 @@ function MemChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const { t } = useTranslation();
@@ -1121,8 +1116,7 @@ function MemChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { mem, swap } = formatNezhaInfo(wsData.now, server);
@@ -1339,7 +1333,7 @@ function DiskChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const { t } = useTranslation();
@@ -1383,8 +1377,7 @@ function DiskChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { disk } = formatNezhaInfo(wsData.now, server);
@@ -1553,7 +1546,7 @@ function NetworkChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const { t } = useTranslation();
@@ -1645,8 +1638,7 @@ function NetworkChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { up, down } = formatNezhaInfo(wsData.now, server);
@@ -1861,7 +1853,7 @@ function ConnectChart({
}: {
now: number;
data: NezhaServer;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
period: ChartPeriod;
}) {
const [connectChartData, setConnectChartData] = useState(
@@ -1951,8 +1943,7 @@ function ConnectChart({
messageHistory.length > 0
) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
const server = wsData.servers.find((s) => s.id === data.id);
if (!server) return null;
const { tcp, udp } = formatNezhaInfo(wsData.now, server);
diff --git a/src/components/ServerDetailSummary.tsx b/src/components/ServerDetailSummary.tsx
index f6f3bc1..16546b1 100644
--- a/src/components/ServerDetailSummary.tsx
+++ b/src/components/ServerDetailSummary.tsx
@@ -3,22 +3,19 @@
import { Progress } from "@/components/ui/progress";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
import { formatNezhaInfo } from "@/lib/utils";
-import type { NezhaWebsocketResponse } from "@/types/nezha-api";
export default function ServerDetailSummary({
server_id,
}: {
server_id: number;
}) {
- const { lastMessage, connected } = useWebSocketContext();
+ const { lastData, connected } = useWebSocketContext();
- if (!connected && !lastMessage) {
+ if (!connected && !lastData) {
return null;
}
- const nezhaWsData = lastMessage
- ? (JSON.parse(lastMessage.data) as NezhaWebsocketResponse)
- : null;
+ const nezhaWsData = lastData;
if (!nezhaWsData) {
return null;
diff --git a/src/context/websocket-context.ts b/src/context/websocket-context.ts
index e309c60..f0add70 100644
--- a/src/context/websocket-context.ts
+++ b/src/context/websocket-context.ts
@@ -1,16 +1,17 @@
import { createContext } from "react";
+import type { NezhaWebsocketResponse } from "@/types/nezha-api";
export interface WebSocketContextType {
- lastMessage: { data: string } | null;
+ lastData: NezhaWebsocketResponse | null;
connected: boolean;
- messageHistory: { data: string }[];
+ messageHistory: NezhaWebsocketResponse[];
reconnect: () => void;
needReconnect: boolean;
setNeedReconnect: (needReconnect: boolean) => void;
}
export const WebSocketContext = createContext({
- lastMessage: null,
+ lastData: null,
connected: false,
messageHistory: [],
reconnect: () => {},
diff --git a/src/context/websocket-provider.tsx b/src/context/websocket-provider.tsx
index eaebdca..55c77c1 100644
--- a/src/context/websocket-provider.tsx
+++ b/src/context/websocket-provider.tsx
@@ -1,6 +1,6 @@
import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react";
-
+import type { NezhaWebsocketResponse } from "@/types/nezha-api";
import {
WebSocketContext,
type WebSocketContextType,
@@ -15,8 +15,10 @@ export const WebSocketProvider: React.FC = ({
url,
children,
}) => {
- const [lastMessage, setLastMessage] = useState<{ data: string } | null>(null);
- const [messageHistory, setMessageHistory] = useState<{ data: string }[]>([]); // 新增历史消息状态
+ const [lastData, setLastData] = useState(null);
+ const [messageHistory, setMessageHistory] = useState<
+ NezhaWebsocketResponse[]
+ >([]);
const [connected, setConnected] = useState(false);
const [needReconnect, setNeedReconnect] = useState(false);
const ws = useRef(null);
@@ -85,13 +87,21 @@ export const WebSocketProvider: React.FC = ({
};
ws.current.onmessage = (event) => {
- const newMessage = { data: event.data };
- setLastMessage(newMessage);
- // 更新历史消息,保持最新的30条记录
- setMessageHistory((prev) => {
- const updated = [newMessage, ...prev];
- return updated.slice(0, 30);
- });
+ try {
+ if (typeof event.data !== "string") {
+ throw new Error("WebSocket message data must be a string");
+ }
+
+ const newData = JSON.parse(event.data) as NezhaWebsocketResponse;
+ setLastData(newData);
+ // 更新历史消息,保持最新的30条记录
+ setMessageHistory((prev) => {
+ const updated = [newData, ...prev];
+ return updated.slice(0, 30);
+ });
+ } catch (error) {
+ console.error("Failed to parse WebSocket message:", error);
+ }
};
ws.current.onerror = (error) => {
@@ -130,7 +140,7 @@ export const WebSocketProvider: React.FC = ({
}, [cleanup, connect]);
const contextValue: WebSocketContextType = {
- lastMessage,
+ lastData,
connected,
messageHistory,
reconnect,
diff --git a/src/hooks/use-chart-history.ts b/src/hooks/use-chart-history.ts
index f5f1a38..09cdf0f 100644
--- a/src/hooks/use-chart-history.ts
+++ b/src/hooks/use-chart-history.ts
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
import type { NezhaWebsocketResponse } from "@/types/nezha-api";
export function useChartHistory(
- messageHistory: { data: string }[],
+ messageHistory: NezhaWebsocketResponse[],
serverId: number,
formatFn: (wsData: NezhaWebsocketResponse, serverId: number) => T | null,
) {
@@ -11,8 +11,7 @@ export function useChartHistory(
useEffect(() => {
if (messageHistory.length > 0 && data.length === 0) {
const historyData = messageHistory
- .map((msg) => {
- const wsData = JSON.parse(msg.data) as NezhaWebsocketResponse;
+ .map((wsData) => {
return formatFn(wsData, serverId);
})
.filter((item): item is T => item !== null)
diff --git a/src/main.tsx b/src/main.tsx
index f328a2e..f7bf293 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,5 +1,5 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
+import { lazy, Suspense } from "react";
import ReactDOM from "react-dom/client";
import { Toaster } from "sonner";
@@ -15,6 +15,13 @@ import "./i18n";
import "./index.css";
const queryClient = new QueryClient();
+const ReactQueryDevtools = import.meta.env.DEV
+ ? lazy(() =>
+ import("@tanstack/react-query-devtools").then((module) => ({
+ default: module.ReactQueryDevtools,
+ })),
+ )
+ : null;
const rootElement = document.getElementById("root");
if (!rootElement) {
@@ -42,7 +49,11 @@ ReactDOM.createRoot(rootElement).render(
position="top-center"
className={"flex items-center justify-center"}
/>
-
+ {ReactQueryDevtools ? (
+
+
+
+ ) : null}
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index cd56e04..104d9c0 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -22,7 +22,7 @@ import { useStatus } from "@/hooks/use-status";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
import { fetchServerGroup, fetchService } from "@/lib/nezha-api";
import { cn, formatNezhaInfo } from "@/lib/utils";
-import type { NezhaWebsocketResponse, ServerGroup } from "@/types/nezha-api";
+import type { ServerGroup } from "@/types/nezha-api";
export default function Servers() {
const { t } = useTranslation();
@@ -41,7 +41,7 @@ export default function Servers() {
const hasServices =
!!serviceData?.data?.services &&
Object.keys(serviceData.data.services).length > 0;
- const { lastMessage, connected } = useWebSocketContext();
+ const { lastData, connected } = useWebSocketContext();
const { status } = useStatus();
const [showServices, setShowServices] = useState("0");
const [showMap, setShowMap] = useState("0");
@@ -124,9 +124,7 @@ export default function Servers() {
restoreScrollPosition();
}, [restoreScrollPosition]);
- const nezhaWsData = lastMessage
- ? (JSON.parse(lastMessage.data) as NezhaWebsocketResponse)
- : null;
+ const nezhaWsData = lastData;
const groupTabs = [
"All",
@@ -142,7 +140,7 @@ export default function Servers() {
?.map((item: ServerGroup) => item.group.name) || []),
];
- if (!connected && !lastMessage) {
+ if (!connected && !lastData) {
return (
diff --git a/src/pages/ServerDetail.tsx b/src/pages/ServerDetail.tsx
index eb1c238..dac573d 100644
--- a/src/pages/ServerDetail.tsx
+++ b/src/pages/ServerDetail.tsx
@@ -1,11 +1,17 @@
-import { useEffect, useState } from "react";
+import { lazy, Suspense, useEffect, useState } from "react";
import { Navigate, useParams } from "react-router-dom";
-import { NetworkChart } from "@/components/NetworkChart";
+import NetworkChartLoading from "@/components/NetworkChartLoading";
import ServerDetailChart from "@/components/ServerDetailChart";
import ServerDetailOverview from "@/components/ServerDetailOverview";
import TabSwitch from "@/components/TabSwitch";
import { Separator } from "@/components/ui/separator";
+const NetworkChart = lazy(() =>
+ import("@/components/NetworkChart").then((module) => ({
+ default: module.NetworkChart,
+ })),
+);
+
export default function ServerDetail() {
useEffect(() => {
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
@@ -39,15 +45,12 @@ export default function ServerDetail() {
*/}
-
-
-
-
-
-
+ {currentTab === tabs[0] &&
}
+ {currentTab === tabs[1] && (
+
}>
+
+
+ )}
);
}
diff --git a/src/test/components/dash-command.test.tsx b/src/test/components/dash-command.test.tsx
index 14d89e7..20ef0eb 100644
--- a/src/test/components/dash-command.test.tsx
+++ b/src/test/components/dash-command.test.tsx
@@ -7,7 +7,10 @@ import { createServer } from "@/test/fixtures";
const dashMocks = vi.hoisted(() => ({
closeCommand: vi.fn(),
isOpen: true,
- lastMessage: null as MessageEvent
| null,
+ lastData: null as {
+ now: number;
+ servers: ReturnType[];
+ } | null,
navigate: vi.fn(),
setTheme: vi.fn(),
toggleCommand: vi.fn(),
@@ -31,7 +34,7 @@ vi.mock("@/hooks/use-theme", () => ({
vi.mock("@/hooks/use-websocket-context", () => ({
useWebSocketContext: () => ({
connected: dashMocks.connected,
- lastMessage: dashMocks.lastMessage,
+ lastData: dashMocks.lastData,
}),
}));
@@ -45,24 +48,22 @@ vi.mock("react-router-dom", async (importOriginal) => {
function seedWebSocketData() {
dashMocks.connected = true;
- dashMocks.lastMessage = new MessageEvent("message", {
- data: JSON.stringify({
- now: Date.parse("2025-01-01T00:00:00.000Z") / 1000,
- servers: [
- createServer({
- id: 7,
- name: "edge-7",
- last_active: "2025-01-01T00:00:00.000Z",
- }),
- ],
- }),
- });
+ dashMocks.lastData = {
+ now: Date.parse("2025-01-01T00:00:20.000Z"),
+ servers: [
+ createServer({
+ id: 7,
+ name: "edge-7",
+ last_active: "2025-01-01T00:00:00.000Z",
+ }),
+ ],
+ };
}
describe("DashCommand", () => {
it("does not render until websocket data is available", () => {
dashMocks.connected = false;
- dashMocks.lastMessage = null;
+ dashMocks.lastData = null;
const { container } = render();
diff --git a/src/test/components/header.test.tsx b/src/test/components/header.test.tsx
index 435c45e..b97c071 100644
--- a/src/test/components/header.test.tsx
+++ b/src/test/components/header.test.tsx
@@ -15,7 +15,7 @@ const headerMocks = vi.hoisted(() => ({
connected: true,
fetchLoginUser: vi.fn(),
fetchSetting: vi.fn(),
- lastMessage: null as MessageEvent | null,
+ lastData: null as { now: number; online?: number; servers: [] } | null,
needReconnect: false,
setNeedReconnect: vi.fn(),
updateBackground: vi.fn(),
@@ -37,7 +37,7 @@ vi.mock("@/hooks/use-background", () => ({
vi.mock("@/hooks/use-websocket-context", () => ({
useWebSocketContext: () => ({
connected: headerMocks.connected,
- lastMessage: headerMocks.lastMessage,
+ lastData: headerMocks.lastData,
needReconnect: headerMocks.needReconnect,
setNeedReconnect: headerMocks.setNeedReconnect,
}),
@@ -104,9 +104,11 @@ describe("Header", () => {
headerMocks.connected = true;
headerMocks.fetchLoginUser.mockReset();
headerMocks.fetchSetting.mockReset();
- headerMocks.lastMessage = new MessageEvent("message", {
- data: JSON.stringify({ online: 4 }),
- });
+ headerMocks.lastData = {
+ now: Date.parse("2025-01-01T00:00:20.000Z"),
+ online: 4,
+ servers: [],
+ };
headerMocks.needReconnect = false;
headerMocks.setNeedReconnect.mockReset();
headerMocks.updateBackground.mockReset();
diff --git a/src/test/components/server-detail-chart.test.tsx b/src/test/components/server-detail-chart.test.tsx
index 29b3bb0..0e5bd47 100644
--- a/src/test/components/server-detail-chart.test.tsx
+++ b/src/test/components/server-detail-chart.test.tsx
@@ -6,15 +6,15 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import ServerDetailChart from "@/components/ServerDetailChart";
import { createServer, createSettingResponse } from "@/test/fixtures";
import { createTestQueryClient } from "@/test/utils";
-import type { NezhaServer } from "@/types/nezha-api";
+import type { NezhaServer, NezhaWebsocketResponse } from "@/types/nezha-api";
const detailChartMocks = vi.hoisted(() => ({
connected: true,
fetchLoginUser: vi.fn(),
fetchServerMetrics: vi.fn(),
fetchSetting: vi.fn(),
- lastMessage: null as { data: string } | null,
- messageHistory: [] as { data: string }[],
+ lastData: null as NezhaWebsocketResponse | null,
+ messageHistory: [] as NezhaWebsocketResponse[],
}));
vi.mock("recharts", () => {
@@ -70,7 +70,7 @@ vi.mock("recharts", () => {
vi.mock("@/hooks/use-websocket-context", () => ({
useWebSocketContext: () => ({
connected: detailChartMocks.connected,
- lastMessage: detailChartMocks.lastMessage,
+ lastData: detailChartMocks.lastData,
messageHistory: detailChartMocks.messageHistory,
}),
}));
@@ -122,10 +122,8 @@ function metricsResponse(metric: string) {
function websocketPayload(server: NezhaServer, now: number) {
return {
- data: JSON.stringify({
- now,
- servers: [server],
- }),
+ now,
+ servers: [server],
};
}
@@ -160,7 +158,7 @@ function seedWebSocketData() {
});
detailChartMocks.connected = true;
- detailChartMocks.lastMessage = websocketPayload(server, baseNow);
+ detailChartMocks.lastData = websocketPayload(server, baseNow);
detailChartMocks.messageHistory = [0, 1, 2].map((index) =>
websocketPayload(
createServer({
@@ -192,7 +190,7 @@ describe("ServerDetailChart", () => {
detailChartMocks.fetchLoginUser.mockReset();
detailChartMocks.fetchServerMetrics.mockReset();
detailChartMocks.fetchSetting.mockReset();
- detailChartMocks.lastMessage = null;
+ detailChartMocks.lastData = null;
detailChartMocks.messageHistory = [];
detailChartMocks.fetchLoginUser.mockRejectedValue(new Error("anonymous"));
detailChartMocks.fetchSetting.mockResolvedValue(settingResponse());
diff --git a/src/test/components/server-detail-components.test.tsx b/src/test/components/server-detail-components.test.tsx
index 8b6d526..5983446 100644
--- a/src/test/components/server-detail-components.test.tsx
+++ b/src/test/components/server-detail-components.test.tsx
@@ -8,7 +8,14 @@ import { createServer } from "@/test/fixtures";
const websocketMocks = vi.hoisted(() => ({
connected: true,
- lastMessage: null as MessageEvent | null,
+ lastData: null as {
+ now: number;
+ servers: ReturnType[];
+ } | null,
+}));
+
+vi.mock("@numeric-text/react", () => ({
+ default: ({ value }: { value: string | number }) => {value},
}));
vi.mock("@/hooks/use-websocket-context", () => ({
@@ -20,12 +27,10 @@ function seedWebSocketData({
now = Date.parse("2025-01-01T00:00:20.000Z"),
} = {}) {
websocketMocks.connected = true;
- websocketMocks.lastMessage = new MessageEvent("message", {
- data: JSON.stringify({
- now,
- servers: [server],
- }),
- });
+ websocketMocks.lastData = {
+ now,
+ servers: [server],
+ };
}
function LocationProbe() {
@@ -36,7 +41,7 @@ function LocationProbe() {
describe("ServerDetailSummary", () => {
beforeEach(() => {
websocketMocks.connected = true;
- websocketMocks.lastMessage = null;
+ websocketMocks.lastData = null;
});
it("renders nothing until websocket data exists", () => {
@@ -68,7 +73,7 @@ describe("ServerDetailSummary", () => {
describe("ServerDetailOverview", () => {
beforeEach(() => {
websocketMocks.connected = true;
- websocketMocks.lastMessage = null;
+ websocketMocks.lastData = null;
Object.assign(window, { ForceUseSvgFlag: true });
});
diff --git a/src/test/context/providers.test.tsx b/src/test/context/providers.test.tsx
index 5e54cfd..cf4feb3 100644
--- a/src/test/context/providers.test.tsx
+++ b/src/test/context/providers.test.tsx
@@ -12,6 +12,7 @@ import { useSort } from "@/hooks/use-sort";
import { useStatus } from "@/hooks/use-status";
import { useTooltip } from "@/hooks/use-tooltip";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
+import { createServer } from "@/test/fixtures";
class FakeWebSocket {
static readonly CONNECTING = 0;
@@ -121,7 +122,7 @@ function TooltipProbe() {
function WebSocketProbe() {
const {
connected,
- lastMessage,
+ lastData,
messageHistory,
needReconnect,
setNeedReconnect,
@@ -130,7 +131,7 @@ function WebSocketProbe() {
return (
{connected ? "connected" : "disconnected"}
-
{lastMessage?.data ?? "none"}
+
{lastData?.servers[0]?.name ?? "none"}
{messageHistory.length}
{needReconnect ? "needs-reconnect" : "stable"}
);
}
diff --git a/src/components/VirtualServerList.tsx b/src/components/VirtualServerList.tsx
new file mode 100644
index 0000000..ef62b17
--- /dev/null
+++ b/src/components/VirtualServerList.tsx
@@ -0,0 +1,159 @@
+import { useWindowVirtualizer } from "@tanstack/react-virtual";
+import { useEffect, useState } from "react";
+import ServerCard from "@/components/ServerCard";
+import ServerCardInline from "@/components/ServerCardInline";
+import type { NezhaServer } from "@/types/nezha-api";
+
+type VirtualServerListProps = {
+ now: number;
+ servers: NezhaServer[];
+ inline: boolean;
+};
+
+const CARD_ROW_GAP = 8;
+const CARD_COLUMNS_BREAKPOINT = 768;
+
+function useCardColumnCount(enabled: boolean) {
+ const [columnCount, setColumnCount] = useState(() => {
+ if (!enabled || typeof window === "undefined") return 1;
+ return window.innerWidth >= CARD_COLUMNS_BREAKPOINT ? 2 : 1;
+ });
+
+ useEffect(() => {
+ if (!enabled) {
+ setColumnCount(1);
+ return;
+ }
+
+ const updateColumnCount = () => {
+ setColumnCount(window.innerWidth >= CARD_COLUMNS_BREAKPOINT ? 2 : 1);
+ };
+
+ updateColumnCount();
+ window.addEventListener("resize", updateColumnCount);
+
+ return () => {
+ window.removeEventListener("resize", updateColumnCount);
+ };
+ }, [enabled]);
+
+ return columnCount;
+}
+
+export default function VirtualServerList({
+ inline,
+ now,
+ servers,
+}: VirtualServerListProps) {
+ if (inline) {
+ return ;
+ }
+
+ return ;
+}
+
+function VirtualCardServerList({
+ now,
+ servers,
+}: {
+ now: number;
+ servers: NezhaServer[];
+}) {
+ const columnCount = useCardColumnCount(true);
+ const rowCount = Math.ceil(servers.length / columnCount);
+
+ const virtualizer = useWindowVirtualizer({
+ count: rowCount,
+ estimateSize: () => 150,
+ gap: CARD_ROW_GAP,
+ overscan: 6,
+ });
+
+ const virtualItems = virtualizer.getVirtualItems();
+
+ return (
+
+
+ {virtualItems.map((virtualRow) => {
+ const rowStart = virtualRow.index * columnCount;
+ const row = servers.slice(rowStart, rowStart + columnCount);
+
+ return (
+
+ {row.map((serverInfo) => (
+
+ ))}
+
+ );
+ })}
+
+
+ );
+}
+
+function VirtualInlineServerList({
+ now,
+ servers,
+}: {
+ now: number;
+ servers: NezhaServer[];
+}) {
+ const virtualizer = useWindowVirtualizer({
+ count: servers.length,
+ estimateSize: () => 86,
+ gap: CARD_ROW_GAP,
+ overscan: 8,
+ });
+
+ const virtualItems = virtualizer.getVirtualItems();
+
+ return (
+
+
+ {virtualItems.map((virtualRow) => {
+ const serverInfo = servers[virtualRow.index];
+ if (!serverInfo) return null;
+
+ return (
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index 218e8f3..d1cebae 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -7,22 +7,41 @@ import {
ViewColumnsIcon,
} from "@heroicons/react/20/solid";
import { useQuery } from "@tanstack/react-query";
-import { useCallback, useEffect, useRef, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import GlobalMap from "@/components/GlobalMap";
import GroupSwitch from "@/components/GroupSwitch";
import { Loader } from "@/components/loading/Loader";
-import ServerCard from "@/components/ServerCard";
-import ServerCardInline from "@/components/ServerCardInline";
import ServerOverview from "@/components/ServerOverview";
import { ServiceTracker } from "@/components/ServiceTracker";
+import VirtualServerList from "@/components/VirtualServerList";
import { SORT_TYPES } from "@/context/sort-context";
import { useSort } from "@/hooks/use-sort";
import { useStatus } from "@/hooks/use-status";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
import { fetchServerGroup, fetchService } from "@/lib/nezha-api";
-import { cn, formatNezhaInfo } from "@/lib/utils";
-import type { ServerGroup } from "@/types/nezha-api";
+import { cn } from "@/lib/utils";
+import type { NezhaServer, ServerGroup } from "@/types/nezha-api";
+
+type PreparedServer = {
+ online: boolean;
+ server: NezhaServer;
+};
+
+const EMPTY_SERVER_LIST: NezhaServer[] = [];
+
+const isServerOnline = (now: number, server: NezhaServer) => {
+ const lastActiveTime = server.last_active.startsWith("000")
+ ? 0
+ : Date.parse(server.last_active);
+
+ return now - lastActiveTime <= 30000;
+};
+
+const getUsagePercent = (used = 0, total = 0) => {
+ if (!total) return 0;
+ return (used / total) * 100;
+};
export default function Servers() {
const { t } = useTranslation();
@@ -140,19 +159,195 @@ export default function Servers() {
}
}, [nezhaWsData, restoreScrollPosition]);
- const groupTabs = [
- "All",
- ...(groupData?.data
- ?.filter((item: ServerGroup) => {
- return (
- Array.isArray(item.servers) &&
- item.servers.some((serverId) =>
- nezhaWsData?.servers?.some((server) => server.id === serverId),
- )
- );
- })
- ?.map((item: ServerGroup) => item.group.name) || []),
- ];
+ const groupServerIdSets = useMemo(() => {
+ const sets = new Map>();
+
+ for (const item of groupData?.data ?? []) {
+ if (Array.isArray(item.servers)) {
+ sets.set(item.group.name, new Set(item.servers));
+ }
+ }
+
+ return sets;
+ }, [groupData?.data]);
+
+ const groupTabs = useMemo(
+ () => [
+ "All",
+ ...(groupData?.data?.map((item: ServerGroup) => item.group.name) || []),
+ ],
+ [groupData?.data],
+ );
+ const {
+ down,
+ downSpeed,
+ filteredServers,
+ offlineServers,
+ onlineServers,
+ totalServers,
+ up,
+ upSpeed,
+ } = useMemo(() => {
+ if (!nezhaWsData) {
+ return {
+ down: 0,
+ downSpeed: 0,
+ filteredServers: EMPTY_SERVER_LIST,
+ offlineServers: 0,
+ onlineServers: 0,
+ totalServers: 0,
+ up: 0,
+ upSpeed: 0,
+ };
+ }
+
+ const currentGroupServerIds = groupServerIdSets.get(currentGroup);
+ const groupFilteredServers: PreparedServer[] = [];
+ const overview = {
+ down: 0,
+ downSpeed: 0,
+ offlineServers: 0,
+ onlineServers: 0,
+ up: 0,
+ upSpeed: 0,
+ };
+
+ for (const server of nezhaWsData.servers) {
+ if (currentGroup !== "All" && !currentGroupServerIds?.has(server.id)) {
+ continue;
+ }
+
+ const online = isServerOnline(nezhaWsData.now, server);
+
+ groupFilteredServers.push({
+ online,
+ server,
+ });
+
+ if (!online) {
+ overview.offlineServers += 1;
+ continue;
+ }
+
+ overview.onlineServers += 1;
+ overview.up += server.state?.net_out_transfer ?? 0;
+ overview.down += server.state?.net_in_transfer ?? 0;
+ overview.upSpeed += server.state?.net_out_speed ?? 0;
+ overview.downSpeed += server.state?.net_in_speed ?? 0;
+ }
+
+ const statusFilteredServers =
+ status === "all"
+ ? groupFilteredServers
+ : groupFilteredServers.filter((item) =>
+ status === "online" ? item.online : !item.online,
+ );
+
+ if (sortType === "default") {
+ const onlineServers: NezhaServer[] = [];
+ const offlineServers: NezhaServer[] = [];
+
+ for (const item of statusFilteredServers) {
+ if (item.online) {
+ onlineServers.push(item.server);
+ } else {
+ offlineServers.push(item.server);
+ }
+ }
+
+ return {
+ ...overview,
+ filteredServers: [...onlineServers, ...offlineServers],
+ totalServers: groupFilteredServers.length,
+ };
+ }
+
+ const sortedServers = [...statusFilteredServers].sort((a, b) => {
+ if (sortType !== "name") {
+ if (!a.online && b.online) return 1;
+ if (a.online && !b.online) return -1;
+ if (!a.online && !b.online) {
+ return 0;
+ }
+ }
+
+ let comparison = 0;
+
+ switch (sortType) {
+ case "name":
+ comparison = a.server.name.localeCompare(b.server.name);
+ break;
+ case "uptime":
+ comparison =
+ (a.server.state?.uptime ?? 0) - (b.server.state?.uptime ?? 0);
+ break;
+ case "system":
+ comparison = (a.server.host?.platform ?? "").localeCompare(
+ b.server.host?.platform ?? "",
+ );
+ break;
+ case "cpu":
+ comparison = (a.server.state?.cpu ?? 0) - (b.server.state?.cpu ?? 0);
+ break;
+ case "mem":
+ comparison =
+ getUsagePercent(
+ a.server.state?.mem_used,
+ a.server.host?.mem_total,
+ ) -
+ getUsagePercent(b.server.state?.mem_used, b.server.host?.mem_total);
+ break;
+ case "disk":
+ comparison =
+ getUsagePercent(
+ a.server.state?.disk_used,
+ a.server.host?.disk_total,
+ ) -
+ getUsagePercent(
+ b.server.state?.disk_used,
+ b.server.host?.disk_total,
+ );
+ break;
+ case "up":
+ comparison =
+ (a.server.state?.net_out_speed ?? 0) -
+ (b.server.state?.net_out_speed ?? 0);
+ break;
+ case "down":
+ comparison =
+ (a.server.state?.net_in_speed ?? 0) -
+ (b.server.state?.net_in_speed ?? 0);
+ break;
+ case "up total":
+ comparison =
+ (a.server.state?.net_out_transfer ?? 0) -
+ (b.server.state?.net_out_transfer ?? 0);
+ break;
+ case "down total":
+ comparison =
+ (a.server.state?.net_in_transfer ?? 0) -
+ (b.server.state?.net_in_transfer ?? 0);
+ break;
+ default:
+ comparison = 0;
+ }
+
+ return sortOrder === "asc" ? comparison : -comparison;
+ });
+
+ return {
+ ...overview,
+ filteredServers: sortedServers.map((item) => item.server),
+ totalServers: groupFilteredServers.length,
+ };
+ }, [
+ currentGroup,
+ groupServerIdSets,
+ nezhaWsData,
+ sortOrder,
+ sortType,
+ status,
+ ]);
if (!connected && !lastData) {
return (
@@ -173,137 +368,6 @@ export default function Servers() {
);
}
- let filteredServers =
- nezhaWsData?.servers?.filter((server) => {
- if (currentGroup === "All") return true;
- const group = groupData?.data?.find(
- (g: ServerGroup) =>
- g.group.name === currentGroup &&
- Array.isArray(g.servers) &&
- g.servers.includes(server.id),
- );
- return !!group;
- }) || [];
-
- const totalServers = filteredServers.length || 0;
- const onlineServers =
- filteredServers.filter(
- (server) => formatNezhaInfo(nezhaWsData.now, server).online,
- )?.length || 0;
- const offlineServers =
- filteredServers.filter(
- (server) => !formatNezhaInfo(nezhaWsData.now, server).online,
- )?.length || 0;
- const up =
- filteredServers.reduce(
- (total, server) =>
- formatNezhaInfo(nezhaWsData.now, server).online
- ? total + (server.state?.net_out_transfer ?? 0)
- : total,
- 0,
- ) || 0;
- const down =
- filteredServers.reduce(
- (total, server) =>
- formatNezhaInfo(nezhaWsData.now, server).online
- ? total + (server.state?.net_in_transfer ?? 0)
- : total,
- 0,
- ) || 0;
-
- const upSpeed =
- filteredServers.reduce(
- (total, server) =>
- formatNezhaInfo(nezhaWsData.now, server).online
- ? total + (server.state?.net_out_speed ?? 0)
- : total,
- 0,
- ) || 0;
- const downSpeed =
- filteredServers.reduce(
- (total, server) =>
- formatNezhaInfo(nezhaWsData.now, server).online
- ? total + (server.state?.net_in_speed ?? 0)
- : total,
- 0,
- ) || 0;
-
- filteredServers =
- status === "all"
- ? filteredServers
- : filteredServers.filter((server) =>
- [status].includes(
- formatNezhaInfo(nezhaWsData.now, server).online
- ? "online"
- : "offline",
- ),
- );
-
- filteredServers = filteredServers.sort((a, b) => {
- const serverAInfo = formatNezhaInfo(nezhaWsData.now, a);
- const serverBInfo = formatNezhaInfo(nezhaWsData.now, b);
-
- if (sortType !== "name") {
- // 仅在非 "name" 排序时,先按在线状态排序
- if (!serverAInfo.online && serverBInfo.online) return 1;
- if (serverAInfo.online && !serverBInfo.online) return -1;
- if (!serverAInfo.online && !serverBInfo.online) {
- // 如果两者都离线,可以继续按照其他条件排序,或者保持原序
- // 这里选择保持原序
- return 0;
- }
- }
-
- let comparison = 0;
-
- switch (sortType) {
- case "name":
- comparison = a.name.localeCompare(b.name);
- break;
- case "uptime":
- comparison = (a.state?.uptime ?? 0) - (b.state?.uptime ?? 0);
- break;
- case "system":
- comparison = (a.host?.platform ?? "").localeCompare(
- b.host?.platform ?? "",
- );
- break;
- case "cpu":
- comparison = (a.state?.cpu ?? 0) - (b.state?.cpu ?? 0);
- break;
- case "mem":
- comparison =
- (formatNezhaInfo(nezhaWsData.now, a).mem ?? 0) -
- (formatNezhaInfo(nezhaWsData.now, b).mem ?? 0);
- break;
- case "disk":
- comparison =
- (formatNezhaInfo(nezhaWsData.now, a).disk ?? 0) -
- (formatNezhaInfo(nezhaWsData.now, b).disk ?? 0);
- break;
- case "up":
- comparison =
- (a.state?.net_out_speed ?? 0) - (b.state?.net_out_speed ?? 0);
- break;
- case "down":
- comparison =
- (a.state?.net_in_speed ?? 0) - (b.state?.net_in_speed ?? 0);
- break;
- case "up total":
- comparison =
- (a.state?.net_out_transfer ?? 0) - (b.state?.net_out_transfer ?? 0);
- break;
- case "down total":
- comparison =
- (a.state?.net_in_transfer ?? 0) - (b.state?.net_in_transfer ?? 0);
- break;
- default:
- comparison = 0;
- }
-
- return sortOrder === "asc" ? comparison : -comparison;
- });
-
return (
)}
{showServices === "1" && }
- {inline === "1" && (
-
- {filteredServers.map((serverInfo) => (
-
- ))}
-
- )}
- {inline === "0" && (
-
- {filteredServers.map((serverInfo) => (
-
- ))}
-
- )}
+
);
}
diff --git a/src/test/components/dash-command.test.tsx b/src/test/components/dash-command.test.tsx
index a909fee..0cf7f6a 100644
--- a/src/test/components/dash-command.test.tsx
+++ b/src/test/components/dash-command.test.tsx
@@ -1,6 +1,6 @@
import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-import { describe, expect, it, vi } from "vitest";
+import { beforeEach, describe, expect, it, vi } from "vitest";
import { DashCommand } from "@/components/DashCommand";
import { createServer } from "@/test/fixtures";
@@ -61,6 +61,16 @@ function seedWebSocketData() {
}
describe("DashCommand", () => {
+ beforeEach(() => {
+ dashMocks.closeCommand.mockClear();
+ dashMocks.navigate.mockClear();
+ dashMocks.setTheme.mockClear();
+ dashMocks.toggleCommand.mockClear();
+ dashMocks.isOpen = true;
+ dashMocks.connected = true;
+ dashMocks.lastData = null;
+ });
+
it("does not render until websocket data is available", () => {
dashMocks.connected = false;
dashMocks.lastData = null;
@@ -70,6 +80,15 @@ describe("DashCommand", () => {
expect(container).toBeEmptyDOMElement();
});
+ it("does not mount server command items while the dialog is closed", () => {
+ seedWebSocketData();
+ dashMocks.isOpen = false;
+
+ render();
+
+ expect(screen.queryByText("edge-7")).not.toBeInTheDocument();
+ });
+
it("renders server and shortcut commands, handles selection, and listens for keyboard toggle", async () => {
const user = userEvent.setup();
seedWebSocketData();
diff --git a/src/test/components/global-map.test.tsx b/src/test/components/global-map.test.tsx
index a5b8fdd..73b039a 100644
--- a/src/test/components/global-map.test.tsx
+++ b/src/test/components/global-map.test.tsx
@@ -87,27 +87,27 @@ describe("InteractiveMap", () => {
width={900}
height={500}
filteredFeatures={filteredFeatures}
- nezhaServerList={[
- createServer({
- id: 11,
- name: "us-online",
- country_code: "us",
- last_active: "2025-01-01T00:00:00.000Z",
- }),
- createServer({
- id: 12,
- name: "us-offline",
- country_code: "us",
- last_active: "2024-12-31T00:00:00.000Z",
- }),
- createServer({
- id: 13,
- name: "sg-edge",
- country_code: "sg",
- last_active: "2025-01-01T00:00:00.000Z",
- }),
- ]}
- now={now}
+ countryServers={{
+ US: [
+ {
+ id: 11,
+ name: "us-online",
+ status: true,
+ },
+ {
+ id: 12,
+ name: "us-offline",
+ status: false,
+ },
+ ],
+ SG: [
+ {
+ id: 13,
+ name: "sg-edge",
+ status: true,
+ },
+ ],
+ }}
/>,
);
@@ -149,14 +149,15 @@ describe("InteractiveMap", () => {
width={900}
height={500}
filteredFeatures={filteredFeatures}
- nezhaServerList={[
- createServer({
- id: 11,
- name: "us-online",
- country_code: "us",
- }),
- ]}
- now={now}
+ countryServers={{
+ US: [
+ {
+ id: 11,
+ name: "us-online",
+ status: true,
+ },
+ ],
+ }}
/>,
);
diff --git a/src/test/pages/Server.test.tsx b/src/test/pages/Server.test.tsx
index 5c0a783..fb2a525 100644
--- a/src/test/pages/Server.test.tsx
+++ b/src/test/pages/Server.test.tsx
@@ -339,7 +339,28 @@ describe("Servers page", () => {
lastData: websocketPayload([createServer({ id: 1, name: "alpha" })]),
});
- expect(scrollTo).not.toHaveBeenCalled();
+ expect(scrollTo).not.toHaveBeenCalledWith({
+ top: 345,
+ left: 0,
+ behavior: "auto",
+ });
+ });
+
+ it("virtualizes large server lists instead of rendering every card", () => {
+ const servers = Array.from({ length: 2000 }, (_, index) =>
+ createServer({ id: index + 1, name: `server-${index + 1}` }),
+ );
+
+ renderServerPage({
+ connected: true,
+ lastData: websocketPayload(servers),
+ });
+
+ expect(screen.getByTestId("server-overview")).toHaveTextContent(
+ "2000:2000:0",
+ );
+ expect(screen.getAllByTestId("server-card").length).toBeLessThan(2000);
+ expect(screen.getAllByTestId("server-card").length).toBeGreaterThan(0);
});
it("toggles map and service tracker controls when service data exists", async () => {
From d295d549da76239c6dc0a6febc780559d68f7b81 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 5 Jul 2026 04:19:39 +0800
Subject: [PATCH 51/64] refactor: optimize ServerDetail loading and update
MapTooltip positioning logic
---
src/App.tsx | 32 +++++---------------
src/components/MapTooltip.tsx | 10 +++++-
src/test/components/info-components.test.tsx | 3 ++
3 files changed, 19 insertions(+), 26 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 4205103..3240569 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -8,7 +8,6 @@ import { DashCommand } from "./components/DashCommand";
import ErrorBoundary from "./components/ErrorBoundary";
import Footer from "./components/Footer";
import Header, { RefreshToast } from "./components/Header";
-import { Skeleton } from "./components/ui/skeleton";
import { useBackground } from "./hooks/use-background";
import { useTheme } from "./hooks/use-theme";
import { InjectContext } from "./lib/inject";
@@ -18,29 +17,8 @@ import ErrorPage from "./pages/ErrorPage";
import Server from "./pages/Server";
const NotFound = lazy(() => import("./pages/NotFound"));
-const ServerDetail = lazy(() => import("./pages/ServerDetail"));
-
-function ServerDetailRouteFallback() {
- return (
-
- );
-}
+const loadServerDetail = () => import("./pages/ServerDetail");
+const ServerDetail = lazy(loadServerDetail);
// Route checker component
const RouteChecker: React.FC = () => {
@@ -59,6 +37,10 @@ const MainApp: React.FC = () => {
const [isCustomCodeInjected, setIsCustomCodeInjected] = useState(false);
const { backgroundImage: customBackgroundImage } = useBackground();
+ useEffect(() => {
+ loadServerDetail();
+ }, []);
+
useEffect(() => {
if (settingData?.data?.config?.custom_code) {
InjectContext(settingData?.data?.config?.custom_code);
@@ -137,7 +119,7 @@ const MainApp: React.FC = () => {
}>
+
}
diff --git a/src/components/MapTooltip.tsx b/src/components/MapTooltip.tsx
index d8da965..0a39a90 100644
--- a/src/components/MapTooltip.tsx
+++ b/src/components/MapTooltip.tsx
@@ -11,14 +11,22 @@ const MapTooltip = memo(function MapTooltip() {
if (!tooltipData) return null;
+ const verticalPlacement =
+ tooltipData.centroid[1] < 120
+ ? "translate(20%, 8px)"
+ : tooltipData.centroid[1] > 380
+ ? "translate(20%, calc(-100% - 8px))"
+ : "translate(20%, -50%)";
+
return (
{
e.stopPropagation();
diff --git a/src/test/components/info-components.test.tsx b/src/test/components/info-components.test.tsx
index 11036c6..bbed08e 100644
--- a/src/test/components/info-components.test.tsx
+++ b/src/test/components/info-components.test.tsx
@@ -161,6 +161,9 @@ describe("MapTooltip", () => {
);
expect(await screen.findByText("Mainland China")).toBeInTheDocument();
+ expect(screen.getByTestId("map-tooltip")).toHaveStyle({
+ transform: "translate(20%, 8px)",
+ });
expect(screen.getByText("2 map.Servers")).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: /edge-2/ }));
From 056c357b6ef6f03d59d5762f561ec91b7421fe59 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 5 Jul 2026 13:17:36 +0800
Subject: [PATCH 52/64] feat: implement backend error handling and improve
error messaging in Server component
---
src/App.tsx | 19 +++---
src/components/Footer.tsx | 1 +
src/components/Header.tsx | 1 +
src/components/ServerFlag.tsx | 16 +++--
src/components/ServiceTracker.tsx | 1 +
src/locales/en/translation.json | 4 +-
src/locales/zh-CN/translation.json | 4 +-
src/locales/zh-TW/translation.json | 4 +-
src/pages/Server.tsx | 47 ++++++++++++++-
src/test/app.test.tsx | 63 +++++++++++++++++---
src/test/components/info-components.test.tsx | 11 ++++
src/test/pages/Server.test.tsx | 43 ++++++++++++-
12 files changed, 187 insertions(+), 27 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 3240569..c328b13 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -25,12 +25,18 @@ const RouteChecker: React.FC = () => {
return
;
};
+const toError = (error: unknown) => {
+ if (!error) return null;
+ return error instanceof Error ? error : new Error(String(error));
+};
+
const MainApp: React.FC = () => {
const { data: settingData, error } = useQuery({
queryKey: ["setting"],
queryFn: () => fetchSetting(),
refetchOnMount: true,
refetchOnWindowFocus: true,
+ retry: false,
});
const { i18n } = useTranslation();
const { setTheme } = useTheme();
@@ -59,13 +65,7 @@ const MainApp: React.FC = () => {
}
}, [forceTheme, setTheme]);
- if (error) {
- return
;
- }
-
- if (!settingData) {
- return null;
- }
+ const initialBackendError = !settingData ? toError(error) : null;
if (settingData?.data?.config?.custom_code && !isCustomCodeInjected) {
return null;
@@ -115,7 +115,10 @@ const MainApp: React.FC = () => {
- } />
+ }
+ />
{
queryFn: () => fetchSetting(),
refetchOnMount: true,
refetchOnWindowFocus: true,
+ retry: false,
});
return (
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 8a5db4f..26455cf 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -58,6 +58,7 @@ function Header() {
queryFn: () => fetchSetting(),
refetchOnMount: true,
refetchOnWindowFocus: true,
+ retry: false,
});
const { lastData, connected } = useWebSocketContext();
diff --git a/src/components/ServerFlag.tsx b/src/components/ServerFlag.tsx
index 7936a02..8da9e74 100644
--- a/src/components/ServerFlag.tsx
+++ b/src/components/ServerFlag.tsx
@@ -1,7 +1,11 @@
+import { hasFlag } from "country-flag-icons";
import getUnicodeFlagIcon from "country-flag-icons/unicode";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
+const normalizeCountryCode = (countryCode: string) =>
+ countryCode.trim().replace(/_/g, "-").toUpperCase();
+
export default function ServerFlag({
country_code,
className,
@@ -38,14 +42,18 @@ export default function ServerFlag({
checkEmojiSupport();
}, []);
- if (!country_code) return null;
+ const normalizedCountryCode = normalizeCountryCode(country_code || "");
+ const canRenderSvgFlag = hasFlag(normalizedCountryCode);
+ const canRenderEmojiFlag = /^[A-Z]{2}$/.test(normalizedCountryCode);
+
+ if (!canRenderSvgFlag) return null;
return (
- {forceUseSvgFlag || !supportsEmojiFlags ? (
-
+ {forceUseSvgFlag || !supportsEmojiFlags || !canRenderEmojiFlag ? (
+
) : (
- getUnicodeFlagIcon(country_code)
+ getUnicodeFlagIcon(normalizedCountryCode)
)}
);
diff --git a/src/components/ServiceTracker.tsx b/src/components/ServiceTracker.tsx
index 0bb7743..5dbd9ea 100644
--- a/src/components/ServiceTracker.tsx
+++ b/src/components/ServiceTracker.tsx
@@ -43,6 +43,7 @@ export function ServiceTracker({ serverList }: { serverList: NezhaServer[] }) {
refetchOnMount: true,
refetchOnWindowFocus: true,
refetchInterval: 10000,
+ retry: false,
});
const serviceSummaries = useMemo(() => {
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 222d976..e70a163 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -104,7 +104,9 @@
},
"error": {
"pageNotFound": "Page not found",
- "backToHome": "Back to home"
+ "backToHome": "Back to home",
+ "backendUnavailableTitle": "Backend API unavailable",
+ "backendUnavailableDescription": "The page is still available, but data cannot be loaded right now."
},
"tabSwitch": {
"Detail": "Detail",
diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json
index 48d735b..6605c2e 100644
--- a/src/locales/zh-CN/translation.json
+++ b/src/locales/zh-CN/translation.json
@@ -105,7 +105,9 @@
},
"error": {
"pageNotFound": "页面不存在",
- "backToHome": "回到主页"
+ "backToHome": "回到主页",
+ "backendUnavailableTitle": "后端 API 无法访问",
+ "backendUnavailableDescription": "页面仍会正常显示,但暂时无法加载监控数据。"
},
"tabSwitch": {
"Detail": "详情",
diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json
index 093d1e4..7a54f10 100644
--- a/src/locales/zh-TW/translation.json
+++ b/src/locales/zh-TW/translation.json
@@ -98,7 +98,9 @@
},
"error": {
"pageNotFound": "頁面不存在",
- "backToHome": "回到主頁"
+ "backToHome": "回到主頁",
+ "backendUnavailableTitle": "後端 API 無法存取",
+ "backendUnavailableDescription": "頁面仍會正常顯示,但暫時無法載入監控資料。"
},
"tabSwitch": {
"detail": "詳細資訊",
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index d1cebae..c73c895 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -43,19 +43,54 @@ const getUsagePercent = (used = 0, total = 0) => {
return (used / total) * 100;
};
-export default function Servers() {
+const getErrorMessage = (error: unknown) => {
+ if (!error) return "";
+ if (error instanceof Error) return error.message;
+ return String(error);
+};
+
+function BackendErrorState({ error }: { error: unknown }) {
+ const { t } = useTranslation();
+ const message = getErrorMessage(error);
+
+ return (
+
+
+
+ {t("error.backendUnavailableTitle")}
+
+
+ {t("error.backendUnavailableDescription")}
+
+ {message && (
+
+ {message}
+
+ )}
+
+
+ );
+}
+
+export default function Servers({
+ backendError,
+}: {
+ backendError?: Error | null;
+}) {
const { t } = useTranslation();
const { sortType, sortOrder, setSortOrder, setSortType } = useSort();
- const { data: groupData } = useQuery({
+ const { data: groupData, error: groupError } = useQuery({
queryKey: ["server-group"],
queryFn: () => fetchServerGroup(),
+ retry: false,
});
- const { data: serviceData } = useQuery({
+ const { data: serviceData, error: serviceError } = useQuery({
queryKey: ["service"],
queryFn: () => fetchService(),
refetchOnMount: true,
refetchOnWindowFocus: true,
refetchInterval: 10000,
+ retry: false,
});
const hasServices =
!!serviceData?.data?.services &&
@@ -349,6 +384,12 @@ export default function Servers() {
status,
]);
+ const currentBackendError = backendError || groupError || serviceError;
+
+ if (!nezhaWsData && currentBackendError) {
+ return ;
+ }
+
if (!connected && !lastData) {
return (
diff --git a/src/test/app.test.tsx b/src/test/app.test.tsx
index c036a2e..5f7c474 100644
--- a/src/test/app.test.tsx
+++ b/src/test/app.test.tsx
@@ -25,7 +25,12 @@ vi.mock("../components/Header", () => ({
}));
vi.mock("../pages/Server", () => ({
- default: () =>
server-page
,
+ default: ({ backendError }: { backendError?: Error | null }) => (
+
+
server-page
+ {backendError &&
{backendError.message}
}
+
+ ),
}));
vi.mock("../pages/ServerDetail", () => ({
@@ -69,11 +74,14 @@ function renderApp(route = "/") {
window.history.pushState({}, "", route);
const queryClient = createTestQueryClient();
- return render(
-
-
- ,
- );
+ return {
+ queryClient,
+ ...render(
+
+
+ ,
+ ),
+ };
}
describe("App", () => {
@@ -110,6 +118,20 @@ describe("App", () => {
).toBe(true);
});
+ it("renders the app shell while initial settings are still pending", async () => {
+ appMocks.fetchSetting.mockImplementation(
+ () => new Promise(() => undefined),
+ );
+
+ renderApp();
+
+ expect(await screen.findByText("server-page")).toBeInTheDocument();
+ expect(screen.getByText("refresh-toast")).toBeInTheDocument();
+ expect(screen.getByText("header")).toBeInTheDocument();
+ expect(screen.getByText("dash-command")).toBeInTheDocument();
+ expect(screen.getByText("footer")).toBeInTheDocument();
+ });
+
it("injects custom code before showing the app shell", async () => {
appMocks.fetchSetting.mockResolvedValue(
settingResponse(""),
@@ -125,14 +147,41 @@ describe("App", () => {
expect(await screen.findByText("server-page")).toBeInTheDocument();
});
- it("renders fetch errors through the error page", async () => {
+ it("renders the app shell when initial settings fetch fails", async () => {
appMocks.fetchSetting.mockRejectedValue(new Error("settings failed"));
renderApp();
+ expect(await screen.findByText("server-page")).toBeInTheDocument();
+ expect(screen.getByText("refresh-toast")).toBeInTheDocument();
+ expect(screen.getByText("header")).toBeInTheDocument();
+ expect(screen.getByText("dash-command")).toBeInTheDocument();
+ expect(screen.getByText("footer")).toBeInTheDocument();
expect(await screen.findByText("settings failed")).toBeInTheDocument();
});
+ it("keeps rendering with stale settings when a later settings refetch fails", async () => {
+ let requestCount = 0;
+ appMocks.fetchSetting.mockImplementation(() => {
+ requestCount += 1;
+ return requestCount === 1
+ ? Promise.resolve(settingResponse())
+ : Promise.reject(new Error("settings failed"));
+ });
+
+ const { queryClient } = renderApp();
+
+ expect(await screen.findByText("server-page")).toBeInTheDocument();
+
+ await queryClient.refetchQueries({ queryKey: ["setting"] });
+
+ await waitFor(() => {
+ expect(appMocks.fetchSetting.mock.calls.length).toBeGreaterThanOrEqual(2);
+ });
+ expect(screen.getByText("server-page")).toBeInTheDocument();
+ expect(screen.queryByText("settings failed")).not.toBeInTheDocument();
+ });
+
it("routes server detail paths through the app router", async () => {
renderApp("/server/42");
diff --git a/src/test/components/info-components.test.tsx b/src/test/components/info-components.test.tsx
index bbed08e..886870b 100644
--- a/src/test/components/info-components.test.tsx
+++ b/src/test/components/info-components.test.tsx
@@ -180,6 +180,17 @@ describe("ServerFlag", () => {
expect(container.querySelector(".fi-us")).toBeInTheDocument();
});
+ it("normalizes SVG flag classes and ignores invalid country codes", () => {
+ Object.assign(window, { ForceUseSvgFlag: true });
+ const { container, rerender } = render(
);
+
+ expect(container.querySelector(".fi-us")).toBeInTheDocument();
+
+ rerender(
);
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
it("uses emoji flags when the canvas probe detects support", async () => {
Object.assign(window, { ForceUseSvgFlag: false });
const originalCreateElement = document.createElement.bind(document);
diff --git a/src/test/pages/Server.test.tsx b/src/test/pages/Server.test.tsx
index fb2a525..f8ca860 100644
--- a/src/test/pages/Server.test.tsx
+++ b/src/test/pages/Server.test.tsx
@@ -91,7 +91,10 @@ function StatusControl() {
function renderServerPage(
websocketValue: Partial
,
- { withStatusControl = false } = {},
+ {
+ backendError = null,
+ withStatusControl = false,
+ }: { backendError?: Error | null; withStatusControl?: boolean } = {},
) {
const defaultWebsocketValue: WebSocketContextType = {
lastData: null,
@@ -109,7 +112,7 @@ function renderServerPage(
value={{ ...defaultWebsocketValue, ...websocketValue }}
>
{withStatusControl && }
-
+
,
@@ -178,6 +181,42 @@ describe("Servers page", () => {
expect(screen.getByText("info.processing")).toBeInTheDocument();
});
+ it("renders a centered backend error instead of a 500 page", async () => {
+ renderServerPage(
+ {
+ connected: false,
+ lastData: null,
+ },
+ { backendError: new Error("settings failed") },
+ );
+
+ expect(
+ screen.getByText("error.backendUnavailableTitle"),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText("error.backendUnavailableDescription"),
+ ).toBeInTheDocument();
+ expect(screen.getByText("settings failed")).toBeInTheDocument();
+ expect(
+ screen.queryByText("info.websocketConnecting"),
+ ).not.toBeInTheDocument();
+ });
+
+ it("shows backend query errors while waiting for websocket data", async () => {
+ apiMocks.fetchServerGroup.mockRejectedValue(new Error("group failed"));
+ apiMocks.fetchService.mockRejectedValue(new Error("service failed"));
+
+ renderServerPage({
+ connected: false,
+ lastData: null,
+ });
+
+ expect(
+ await screen.findByText("error.backendUnavailableTitle"),
+ ).toBeInTheDocument();
+ expect(screen.getByText("group failed")).toBeInTheDocument();
+ });
+
it("summarizes online and offline servers from websocket data", async () => {
const online = createServer({ id: 1, name: "alpha" });
const offline = createServer({
From 7424b2bfde302c7e3baabb9658e5790336efe20b Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 5 Jul 2026 13:43:41 +0800
Subject: [PATCH 53/64] refactor: remove @numeric-text/react dependency and
implement NumericText component
---
package.json | 1 -
pnpm-lock.yaml | 18 -----------
src/components/Header.tsx | 2 +-
src/components/NumericText.tsx | 30 +++++++++++++++++++
src/components/ServerDetailOverview.tsx | 2 +-
src/components/ServerOverview.tsx | 2 +-
src/test/components/basic-components.test.tsx | 12 +-------
src/test/components/header.test.tsx | 8 +----
.../server-detail-components.test.tsx | 4 ---
9 files changed, 35 insertions(+), 44 deletions(-)
create mode 100644 src/components/NumericText.tsx
diff --git a/package.json b/package.json
index 3502da6..db4c0fa 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,6 @@
"dependencies": {
"@fontsource/inter": "5.2.8",
"@heroicons/react": "2.2.0",
- "@numeric-text/react": "^0.1.4",
"@radix-ui/react-accordion": "1.2.13",
"@radix-ui/react-checkbox": "1.3.4",
"@radix-ui/react-dialog": "^1.1.18",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9e8b3fb..aa482ee 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,9 +14,6 @@ importers:
'@heroicons/react':
specifier: 2.2.0
version: 2.2.0(react@19.2.7)
- '@numeric-text/react':
- specifier: ^0.1.4
- version: 0.1.4(react@19.2.7)
'@radix-ui/react-accordion':
specifier: 1.2.13
version: 1.2.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -394,14 +391,6 @@ packages:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
- '@numeric-text/core@0.1.4':
- resolution: {integrity: sha512-tMaH5u/kdpw3AP+XJMnDWyq39zVHoP80NCLTFwzVept64dIAMKBNLlYtUK0+EULiyFg6IiSwswmc9tMukV1tLw==}
-
- '@numeric-text/react@0.1.4':
- resolution: {integrity: sha512-i1t18jSzn168nl9jYrC+W1FlPexjy0dbAa9bofykaL44ogu+puLg2f5roVA3xOUgjL6bSojv+wKUA/ZRRshwEw==}
- peerDependencies:
- react: ^18 || ^19
-
'@oxc-project/types@0.137.0':
resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==}
@@ -2270,13 +2259,6 @@ snapshots:
'@tybys/wasm-util': 0.10.3
optional: true
- '@numeric-text/core@0.1.4': {}
-
- '@numeric-text/react@0.1.4(react@19.2.7)':
- dependencies:
- '@numeric-text/core': 0.1.4
- react: 19.2.7
-
'@oxc-project/types@0.137.0': {}
'@radix-ui/number@1.1.2': {}
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 26455cf..5534689 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,4 +1,3 @@
-import NumericText from "@numeric-text/react";
import { useQuery } from "@tanstack/react-query";
import { ImageMinus } from "lucide-react";
import { DateTime } from "luxon";
@@ -16,6 +15,7 @@ import { cn } from "@/lib/utils";
import AnimateCountClient from "./AnimatedCount";
import { LanguageSwitcher } from "./LanguageSwitcher";
import { Loader, LoadingSpinner } from "./loading/Loader";
+import NumericText from "./NumericText";
import { SearchButton } from "./SearchButton";
import { Button } from "./ui/button";
diff --git a/src/components/NumericText.tsx b/src/components/NumericText.tsx
new file mode 100644
index 0000000..ca90127
--- /dev/null
+++ b/src/components/NumericText.tsx
@@ -0,0 +1,30 @@
+import type { ComponentPropsWithoutRef } from "react";
+
+type NumericTextTransition = {
+ duration?: number;
+ easing?: string;
+};
+
+type NumericTextProps = Omit, "children"> & {
+ animated?: boolean;
+ respectMotionPreference?: boolean;
+ transition?: NumericTextTransition;
+ trend?: -1 | 0 | 1;
+ value: number | string;
+};
+
+export default function NumericText({
+ animated,
+ respectMotionPreference,
+ transition,
+ trend,
+ value,
+ ...spanProps
+}: NumericTextProps) {
+ void animated;
+ void respectMotionPreference;
+ void transition;
+ void trend;
+
+ return {value};
+}
diff --git a/src/components/ServerDetailOverview.tsx b/src/components/ServerDetailOverview.tsx
index 66688d6..d02d537 100644
--- a/src/components/ServerDetailOverview.tsx
+++ b/src/components/ServerDetailOverview.tsx
@@ -1,4 +1,3 @@
-import NumericText from "@numeric-text/react";
import countries from "i18n-iso-countries";
import enLocale from "i18n-iso-countries/langs/en.json";
import { useEffect, useState } from "react";
@@ -12,6 +11,7 @@ import { Card, CardContent } from "@/components/ui/card";
import { useWebSocketContext } from "@/hooks/use-websocket-context";
import { formatBytes } from "@/lib/format";
import { cn, formatNezhaInfo } from "@/lib/utils";
+import NumericText from "./NumericText";
import {
Accordion,
AccordionContent,
diff --git a/src/components/ServerOverview.tsx b/src/components/ServerOverview.tsx
index f8e80eb..ed80fcc 100644
--- a/src/components/ServerOverview.tsx
+++ b/src/components/ServerOverview.tsx
@@ -2,12 +2,12 @@ import {
ArrowDownCircleIcon,
ArrowUpCircleIcon,
} from "@heroicons/react/20/solid";
-import NumericText from "@numeric-text/react";
import { useTranslation } from "react-i18next";
import { Card, CardContent } from "@/components/ui/card";
import { useStatus } from "@/hooks/use-status";
import { formatBytes } from "@/lib/format";
import { cn } from "@/lib/utils";
+import NumericText from "./NumericText";
type ServerOverviewProps = {
online: number;
diff --git a/src/test/components/basic-components.test.tsx b/src/test/components/basic-components.test.tsx
index 6d16986..07ec5a1 100644
--- a/src/test/components/basic-components.test.tsx
+++ b/src/test/components/basic-components.test.tsx
@@ -1,6 +1,6 @@
import { fireEvent, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
-import { describe, expect, it, vi } from "vitest";
+import { describe, expect, it } from "vitest";
import AnimateCountClient, { AnimateCount } from "@/components/AnimatedCount";
import ErrorBoundary from "@/components/ErrorBoundary";
import ChartSkeleton from "@/components/loading/ChartSkeleton";
@@ -14,16 +14,6 @@ import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Skeleton } from "@/components/ui/skeleton";
-vi.mock("@numeric-text/react", () => ({
- default: ({
- className,
- value,
- }: {
- className?: string;
- value: string | number;
- }) => {value},
-}));
-
import { CommandProvider } from "@/context/command-provider";
import { StatusProvider } from "@/context/status-provider";
import { useCommand } from "@/hooks/use-command";
diff --git a/src/test/components/header.test.tsx b/src/test/components/header.test.tsx
index 97a8649..ce3ccf2 100644
--- a/src/test/components/header.test.tsx
+++ b/src/test/components/header.test.tsx
@@ -21,12 +21,6 @@ const headerMocks = vi.hoisted(() => ({
updateBackground: vi.fn(),
}));
-vi.mock("@numeric-text/react", () => ({
- default: ({ value }: { value: string | number }) => (
- {value}
- ),
-}));
-
vi.mock("@/hooks/use-background", () => ({
useBackground: () => ({
backgroundImage: headerMocks.backgroundImage,
@@ -150,7 +144,7 @@ describe("Header", () => {
);
expect(screen.getAllByRole("link", { name: "Docs" })).toHaveLength(2);
expect(await screen.findAllByText("dashboard")).toHaveLength(2);
- expect(screen.getByTestId("numeric-text")).toHaveTextContent("4");
+ expect(screen.getByText("online").closest("button")).toHaveTextContent("4");
expect(screen.getByText("online")).toBeInTheDocument();
await waitFor(() => {
diff --git a/src/test/components/server-detail-components.test.tsx b/src/test/components/server-detail-components.test.tsx
index 9c9f2a7..c687be6 100644
--- a/src/test/components/server-detail-components.test.tsx
+++ b/src/test/components/server-detail-components.test.tsx
@@ -14,10 +14,6 @@ const websocketMocks = vi.hoisted(() => ({
} | null,
}));
-vi.mock("@numeric-text/react", () => ({
- default: ({ value }: { value: string | number }) => {value},
-}));
-
vi.mock("@/hooks/use-websocket-context", () => ({
useWebSocketContext: () => websocketMocks,
}));
From 27d8d3f572ab29483d5128bd534c4e81e6d1070e Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 5 Jul 2026 13:46:34 +0800
Subject: [PATCH 54/64] chore(deps): update vite to version 8.1.3 and related
dependencies in lockfile
---
package.json | 2 +-
pnpm-lock.yaml | 216 ++++++++++++++++++++++++-------------------------
2 files changed, 109 insertions(+), 109 deletions(-)
diff --git a/package.json b/package.json
index db4c0fa..956f890 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"postcss": "8.5.15",
"tailwindcss": "^4.3.2",
"typescript": "~6.0.3",
- "vite": "^8.1.2",
+ "vite": "^8.1.3",
"vitest": "^4.1.9",
"ws": "^8.21.0"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index aa482ee..9dcb34b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -149,7 +149,7 @@ importers:
version: 19.2.3(@types/react@19.2.17)
'@vitejs/plugin-react':
specifier: ^6.0.3
- version: 6.0.3(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))
+ version: 6.0.3(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))
'@vitest/coverage-v8':
specifier: ^4.1.9
version: 4.1.9(vitest@4.1.9)
@@ -169,11 +169,11 @@ importers:
specifier: ~6.0.3
version: 6.0.3
vite:
- specifier: ^8.1.2
- version: 8.1.2(@types/node@25.9.2)(jiti@2.7.0)
+ specifier: ^8.1.3
+ version: 8.1.3(@types/node@25.9.2)(jiti@2.7.0)
vitest:
specifier: ^4.1.9
- version: 4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))
+ version: 4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))
ws:
specifier: ^8.21.0
version: 8.21.0
@@ -391,8 +391,8 @@ packages:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
- '@oxc-project/types@0.137.0':
- resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==}
+ '@oxc-project/types@0.138.0':
+ resolution: {integrity: sha512-1a7ZKmrRTCoN1XMZ4L0PyyqrMnrNlLyPuOkdSX2MZg7IiIGRUyurNhAm73ptDOraoBcIordsIGKNPKUzy3ZmfA==}
'@radix-ui/number@1.1.2':
resolution: {integrity: sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==}
@@ -900,97 +900,97 @@ packages:
react-redux:
optional: true
- '@rolldown/binding-android-arm64@1.1.3':
- resolution: {integrity: sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==}
+ '@rolldown/binding-android-arm64@1.1.4':
+ resolution: {integrity: sha512-EZLpf/8y7GXkkra90ML47kzik/GMP3EMcE9bPyHmRfxLC6z9+aW5A8poCsoxjrT5GfEcNAAvWwUHjvP1pUQkfw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
- '@rolldown/binding-darwin-arm64@1.1.3':
- resolution: {integrity: sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==}
+ '@rolldown/binding-darwin-arm64@1.1.4':
+ resolution: {integrity: sha512-aUi+HBvmYb7j8krl1+qJgkG8C17fO79gk3c+jPw4S8glRFc1DTija9S3EyaTSQUm5GJXYKDAsugBEhFHH2vYiQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
- '@rolldown/binding-darwin-x64@1.1.3':
- resolution: {integrity: sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==}
+ '@rolldown/binding-darwin-x64@1.1.4':
+ resolution: {integrity: sha512-F7hHC3gwY11+vByKPRWqwGbeXWVgKmL+pTGCinaEhdihzBV2aQ0fvZOch9cXYUOKuKKq429HeYXOqQLc7wFCEg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
- '@rolldown/binding-freebsd-x64@1.1.3':
- resolution: {integrity: sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==}
+ '@rolldown/binding-freebsd-x64@1.1.4':
+ resolution: {integrity: sha512-sI5yw+7s92SK6odiEhD5lKCBlWcpjHS5qyqpVQbZAJ0fIzEUXrmbl3DH2ybR3PZogulNJF+COLtmA8hUfvkCCQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
- '@rolldown/binding-linux-arm-gnueabihf@1.1.3':
- resolution: {integrity: sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==}
+ '@rolldown/binding-linux-arm-gnueabihf@1.1.4':
+ resolution: {integrity: sha512-mCi0OKgEieFircrtVYmQAFGszRtMnZ6fpZAXrxanXAu7lqZcsK1E1RAaZNG0uKAnxox3B1f4EyQNnoyMfN1vAA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
- '@rolldown/binding-linux-arm64-gnu@1.1.3':
- resolution: {integrity: sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==}
+ '@rolldown/binding-linux-arm64-gnu@1.1.4':
+ resolution: {integrity: sha512-B9Ial3Kv5sh0SHnB1g/QWcUQCEvCF6QKGAl4zXypYj65mVI+B4AhFBwPtSN7pDrJeIx8Z7zdy4ntx+wQABom7w==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-arm64-musl@1.1.3':
- resolution: {integrity: sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==}
+ '@rolldown/binding-linux-arm64-musl@1.1.4':
+ resolution: {integrity: sha512-lZVym0PuHE1KZ22gmFTC15lAkrg9iTszR617oYRB/iPY1A56ywoJzVKOJBKaot5RiikCObmur6pogpse3gRcng==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
- '@rolldown/binding-linux-ppc64-gnu@1.1.3':
- resolution: {integrity: sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==}
+ '@rolldown/binding-linux-ppc64-gnu@1.1.4':
+ resolution: {integrity: sha512-t2DNiLJWNTbnEHyUzTumldML6ET4/g16467LZoDDJ3tSxGvguL5/NyC2lCsNKuyRycg9XeDQF5SSv+TNOhQEXg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-s390x-gnu@1.1.3':
- resolution: {integrity: sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==}
+ '@rolldown/binding-linux-s390x-gnu@1.1.4':
+ resolution: {integrity: sha512-0WIRnL1Uw4BvTZRLQt+PVgo6ZKTJadlC2btP+/EOXv2f/DWbY0rEgl+y834mIVwP1FkTlWVTrGGJXf12lru7EQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-x64-gnu@1.1.3':
- resolution: {integrity: sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==}
+ '@rolldown/binding-linux-x64-gnu@1.1.4':
+ resolution: {integrity: sha512-JWtGshGfX+oENAKonoNkqEJX+7hC8yfhi9GUyPX1VX4mdh1y5r+ZiJLR5XzAB0aoP6s/PcILsGjKq8O0mm24bw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
- '@rolldown/binding-linux-x64-musl@1.1.3':
- resolution: {integrity: sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==}
+ '@rolldown/binding-linux-x64-musl@1.1.4':
+ resolution: {integrity: sha512-rT6yQcxUuXs4CnbofqwHRRV0iem349rLMYpTjkgQGLjrY4ado/eDzwPZPTCgTOlF6Nkp8NEv70yLMTn6qkWxsQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
- '@rolldown/binding-openharmony-arm64@1.1.3':
- resolution: {integrity: sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==}
+ '@rolldown/binding-openharmony-arm64@1.1.4':
+ resolution: {integrity: sha512-KXMGoboq5cyaCQjDA4GLuRiOwBQ0EyFnJoVViLeZ45/3rFItRODEr+NdsBcVpll40hhNArlm/speWGRvj08LzA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
- '@rolldown/binding-wasm32-wasi@1.1.3':
- resolution: {integrity: sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==}
+ '@rolldown/binding-wasm32-wasi@1.1.4':
+ resolution: {integrity: sha512-5K83rb36oJiY7BCyE9zLZtGcPV4g5wvq+xwdO0XPIwDVZI8cyB/AUjkNXGb92/rnmezEkjMOpgY61rtwjQtFwg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [wasm32]
- '@rolldown/binding-win32-arm64-msvc@1.1.3':
- resolution: {integrity: sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==}
+ '@rolldown/binding-win32-arm64-msvc@1.1.4':
+ resolution: {integrity: sha512-PnWBtw3TV5KOg69HQQDR0mnQuyCmSGR2pAB4DC1rPF808fgKeTUMj2EOEyKATpgiuxuR5APQmiDO7PDgEjTFSA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
- '@rolldown/binding-win32-x64-msvc@1.1.3':
- resolution: {integrity: sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==}
+ '@rolldown/binding-win32-x64-msvc@1.1.4':
+ resolution: {integrity: sha512-M1lpniBePobTfsa7Ks9a199e1akxsXn+GYBUKsEzv3YFzOm1HJAMNwKI3qr0Zq+mxwx9gOZoTdP1yXRYsZUocQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
@@ -1433,8 +1433,8 @@ packages:
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
engines: {node: '>=20.19.0'}
- es-module-lexer@2.2.0:
- resolution: {integrity: sha512-3lGxdTXCLfe1MYfTz1y2ksAAUM4NAOP6rPEjxGJVKO7TZ5+tvHCaQWGpC4Y3IXvW3ece0Cz1cIP4FWBxOnGCTQ==}
+ es-module-lexer@2.3.0:
+ resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==}
es-toolkit@1.49.0:
resolution: {integrity: sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==}
@@ -1503,8 +1503,8 @@ packages:
immer@10.2.0:
resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
- immer@11.1.8:
- resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==}
+ immer@11.1.11:
+ resolution: {integrity: sha512-qzXuyXAkPySAGYkfsAwodDPWT8Zm7/Uo5BNt4BjhMhG5WlWyZZ4wQqnWwdS8kjlQ1Cwu6gjw3A6+0gTQwlyYtw==}
indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
@@ -1674,8 +1674,8 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
- picomatch@4.0.4:
- resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
+ picomatch@4.0.5:
+ resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
engines: {node: '>=12'}
postcss@8.5.15:
@@ -1811,8 +1811,8 @@ packages:
reselect@5.1.1:
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
- rolldown@1.1.3:
- resolution: {integrity: sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==}
+ rolldown@1.1.4:
+ resolution: {integrity: sha512-IjZYiLxZwpnhwhdBH2ugdTGVSdhCQUmLxLoqyjiL0JxYjyRst+5a0P3xfrTxJ5F638j4Mvvw5FAX5XE6eHpXbA==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
@@ -1894,11 +1894,11 @@ packages:
resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==}
engines: {node: '>=14.0.0'}
- tldts-core@7.4.5:
- resolution: {integrity: sha512-pGrwzZDvPwKe+7NNUqAunb6rqTfynr0VOUhCMdqbu5xlvNiszsAJygRzwvpVycdzejlbpY+SWJOn+s75Og7FEA==}
+ tldts-core@7.4.6:
+ resolution: {integrity: sha512-TkQNGJIhlEphpHCjKodMTSe23egUZr/g+flI2qkLgiJ/maAzSgXypSLRTNH3nCmqgayEmtcJBiLcfODSAr1xoA==}
- tldts@7.4.5:
- resolution: {integrity: sha512-RfEzKWcq5fHUOFq7J3rl3Oz6ylKGtcHqUznzj4EcXsxLSIjJcvpbXAQtWGeJQ0xKnimR5e0Cn+cn9TssfMzm+g==}
+ tldts@7.4.6:
+ resolution: {integrity: sha512-rbP0Gyx8b3Ae9yO//CU2wbSnQNoQ66m1nJdSbSHmnwKwzkkz/u8mERYU8T2rmlmy+bJvRNn84yNCW8gYqox44Q==}
hasBin: true
tough-cookie@6.0.1:
@@ -1952,8 +1952,8 @@ packages:
victory-vendor@37.3.6:
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
- vite@8.1.2:
- resolution: {integrity: sha512-6YYPbRXTxx6bRXmOn7XdnQAy5DQNHhDgtjhDHI13oe4pY93kkcdGJWxpGwOm++/Wh0QpQhDrpIoVMrmrsI5AGQ==}
+ vite@8.1.3:
+ resolution: {integrity: sha512-Ds+gBRbj0lwRO2Y5hwnUBdxSwlAve9LeRyU4sNnAr0ewW0gWF0n5bgXgUzbgZ49MV9BVUAQUFYVcDUcilUExMA==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -2259,7 +2259,7 @@ snapshots:
'@tybys/wasm-util': 0.10.3
optional: true
- '@oxc-project/types@0.137.0': {}
+ '@oxc-project/types@0.138.0': {}
'@radix-ui/number@1.1.2': {}
@@ -2758,7 +2758,7 @@ snapshots:
dependencies:
'@standard-schema/spec': 1.1.0
'@standard-schema/utils': 0.3.0
- immer: 11.1.8
+ immer: 11.1.11
redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.1.1
@@ -2766,53 +2766,53 @@ snapshots:
react: 19.2.7
react-redux: 9.3.0(@types/react@19.2.17)(react@19.2.7)(redux@5.0.1)
- '@rolldown/binding-android-arm64@1.1.3':
+ '@rolldown/binding-android-arm64@1.1.4':
optional: true
- '@rolldown/binding-darwin-arm64@1.1.3':
+ '@rolldown/binding-darwin-arm64@1.1.4':
optional: true
- '@rolldown/binding-darwin-x64@1.1.3':
+ '@rolldown/binding-darwin-x64@1.1.4':
optional: true
- '@rolldown/binding-freebsd-x64@1.1.3':
+ '@rolldown/binding-freebsd-x64@1.1.4':
optional: true
- '@rolldown/binding-linux-arm-gnueabihf@1.1.3':
+ '@rolldown/binding-linux-arm-gnueabihf@1.1.4':
optional: true
- '@rolldown/binding-linux-arm64-gnu@1.1.3':
+ '@rolldown/binding-linux-arm64-gnu@1.1.4':
optional: true
- '@rolldown/binding-linux-arm64-musl@1.1.3':
+ '@rolldown/binding-linux-arm64-musl@1.1.4':
optional: true
- '@rolldown/binding-linux-ppc64-gnu@1.1.3':
+ '@rolldown/binding-linux-ppc64-gnu@1.1.4':
optional: true
- '@rolldown/binding-linux-s390x-gnu@1.1.3':
+ '@rolldown/binding-linux-s390x-gnu@1.1.4':
optional: true
- '@rolldown/binding-linux-x64-gnu@1.1.3':
+ '@rolldown/binding-linux-x64-gnu@1.1.4':
optional: true
- '@rolldown/binding-linux-x64-musl@1.1.3':
+ '@rolldown/binding-linux-x64-musl@1.1.4':
optional: true
- '@rolldown/binding-openharmony-arm64@1.1.3':
+ '@rolldown/binding-openharmony-arm64@1.1.4':
optional: true
- '@rolldown/binding-wasm32-wasi@1.1.3':
+ '@rolldown/binding-wasm32-wasi@1.1.4':
dependencies:
'@emnapi/core': 1.11.1
'@emnapi/runtime': 1.11.1
'@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
optional: true
- '@rolldown/binding-win32-arm64-msvc@1.1.3':
+ '@rolldown/binding-win32-arm64-msvc@1.1.4':
optional: true
- '@rolldown/binding-win32-x64-msvc@1.1.3':
+ '@rolldown/binding-win32-x64-msvc@1.1.4':
optional: true
'@rolldown/pluginutils@1.0.1': {}
@@ -3017,10 +3017,10 @@ snapshots:
'@types/use-sync-external-store@0.0.6': {}
- '@vitejs/plugin-react@6.0.3(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))':
+ '@vitejs/plugin-react@6.0.3(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))':
dependencies:
'@rolldown/pluginutils': 1.0.1
- vite: 8.1.2(@types/node@25.9.2)(jiti@2.7.0)
+ vite: 8.1.3(@types/node@25.9.2)(jiti@2.7.0)
'@vitest/coverage-v8@4.1.9(vitest@4.1.9)':
dependencies:
@@ -3034,7 +3034,7 @@ snapshots:
obug: 2.1.3
std-env: 4.1.0
tinyrainbow: 3.1.0
- vitest: 4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))
+ vitest: 4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))
'@vitest/expect@4.1.9':
dependencies:
@@ -3045,13 +3045,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
- '@vitest/mocker@4.1.9(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))':
+ '@vitest/mocker@4.1.9(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))':
dependencies:
'@vitest/spy': 4.1.9
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 8.1.2(@types/node@25.9.2)(jiti@2.7.0)
+ vite: 8.1.3(@types/node@25.9.2)(jiti@2.7.0)
'@vitest/pretty-format@4.1.9':
dependencies:
@@ -3212,7 +3212,7 @@ snapshots:
entities@8.0.0: {}
- es-module-lexer@2.2.0: {}
+ es-module-lexer@2.3.0: {}
es-toolkit@1.49.0: {}
@@ -3224,9 +3224,9 @@ snapshots:
expect-type@1.4.0: {}
- fdir@6.5.0(picomatch@4.0.4):
+ fdir@6.5.0(picomatch@4.0.5):
optionalDependencies:
- picomatch: 4.0.4
+ picomatch: 4.0.5
fsevents@2.3.3:
optional: true
@@ -3261,7 +3261,7 @@ snapshots:
immer@10.2.0: {}
- immer@11.1.8: {}
+ immer@11.1.11: {}
indent-string@4.0.0: {}
@@ -3403,7 +3403,7 @@ snapshots:
picocolors@1.1.1: {}
- picomatch@4.0.4: {}
+ picomatch@4.0.5: {}
postcss@8.5.15:
dependencies:
@@ -3532,26 +3532,26 @@ snapshots:
reselect@5.1.1: {}
- rolldown@1.1.3:
+ rolldown@1.1.4:
dependencies:
- '@oxc-project/types': 0.137.0
+ '@oxc-project/types': 0.138.0
'@rolldown/pluginutils': 1.0.1
optionalDependencies:
- '@rolldown/binding-android-arm64': 1.1.3
- '@rolldown/binding-darwin-arm64': 1.1.3
- '@rolldown/binding-darwin-x64': 1.1.3
- '@rolldown/binding-freebsd-x64': 1.1.3
- '@rolldown/binding-linux-arm-gnueabihf': 1.1.3
- '@rolldown/binding-linux-arm64-gnu': 1.1.3
- '@rolldown/binding-linux-arm64-musl': 1.1.3
- '@rolldown/binding-linux-ppc64-gnu': 1.1.3
- '@rolldown/binding-linux-s390x-gnu': 1.1.3
- '@rolldown/binding-linux-x64-gnu': 1.1.3
- '@rolldown/binding-linux-x64-musl': 1.1.3
- '@rolldown/binding-openharmony-arm64': 1.1.3
- '@rolldown/binding-wasm32-wasi': 1.1.3
- '@rolldown/binding-win32-arm64-msvc': 1.1.3
- '@rolldown/binding-win32-x64-msvc': 1.1.3
+ '@rolldown/binding-android-arm64': 1.1.4
+ '@rolldown/binding-darwin-arm64': 1.1.4
+ '@rolldown/binding-darwin-x64': 1.1.4
+ '@rolldown/binding-freebsd-x64': 1.1.4
+ '@rolldown/binding-linux-arm-gnueabihf': 1.1.4
+ '@rolldown/binding-linux-arm64-gnu': 1.1.4
+ '@rolldown/binding-linux-arm64-musl': 1.1.4
+ '@rolldown/binding-linux-ppc64-gnu': 1.1.4
+ '@rolldown/binding-linux-s390x-gnu': 1.1.4
+ '@rolldown/binding-linux-x64-gnu': 1.1.4
+ '@rolldown/binding-linux-x64-musl': 1.1.4
+ '@rolldown/binding-openharmony-arm64': 1.1.4
+ '@rolldown/binding-wasm32-wasi': 1.1.4
+ '@rolldown/binding-win32-arm64-msvc': 1.1.4
+ '@rolldown/binding-win32-x64-msvc': 1.1.4
saxes@6.0.0:
dependencies:
@@ -3604,20 +3604,20 @@ snapshots:
tinyglobby@0.2.17:
dependencies:
- fdir: 6.5.0(picomatch@4.0.4)
- picomatch: 4.0.4
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
tinyrainbow@3.1.0: {}
- tldts-core@7.4.5: {}
+ tldts-core@7.4.6: {}
- tldts@7.4.5:
+ tldts@7.4.6:
dependencies:
- tldts-core: 7.4.5
+ tldts-core: 7.4.6
tough-cookie@6.0.1:
dependencies:
- tldts: 7.4.5
+ tldts: 7.4.6
tr46@6.0.0:
dependencies:
@@ -3667,39 +3667,39 @@ snapshots:
d3-time: 3.1.0
d3-timer: 3.0.1
- vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0):
+ vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0):
dependencies:
lightningcss: 1.32.0
- picomatch: 4.0.4
+ picomatch: 4.0.5
postcss: 8.5.16
- rolldown: 1.1.3
+ rolldown: 1.1.4
tinyglobby: 0.2.17
optionalDependencies:
'@types/node': 25.9.2
fsevents: 2.3.3
jiti: 2.7.0
- vitest@4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0)):
+ vitest@4.1.9(@types/node@25.9.2)(@vitest/coverage-v8@4.1.9)(jsdom@29.1.1)(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0)):
dependencies:
'@vitest/expect': 4.1.9
- '@vitest/mocker': 4.1.9(vite@8.1.2(@types/node@25.9.2)(jiti@2.7.0))
+ '@vitest/mocker': 4.1.9(vite@8.1.3(@types/node@25.9.2)(jiti@2.7.0))
'@vitest/pretty-format': 4.1.9
'@vitest/runner': 4.1.9
'@vitest/snapshot': 4.1.9
'@vitest/spy': 4.1.9
'@vitest/utils': 4.1.9
- es-module-lexer: 2.2.0
+ es-module-lexer: 2.3.0
expect-type: 1.4.0
magic-string: 0.30.21
obug: 2.1.3
pathe: 2.0.3
- picomatch: 4.0.4
+ picomatch: 4.0.5
std-env: 4.1.0
tinybench: 2.9.0
tinyexec: 1.2.4
tinyglobby: 0.2.17
tinyrainbow: 3.1.0
- vite: 8.1.2(@types/node@25.9.2)(jiti@2.7.0)
+ vite: 8.1.3(@types/node@25.9.2)(jiti@2.7.0)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 25.9.2
From 6356d472a76785fefa021e6d188ddf1b6578f8d3 Mon Sep 17 00:00:00 2001
From: jiyuu
Date: Fri, 10 Jul 2026 11:09:07 +0200
Subject: [PATCH 55/64] Translated using Weblate (Japanese)
Currently translated at 18.4% (19 of 103 strings)
Translation: Nezha/User frontend
Translate-URL: https://hosted.weblate.org/projects/nezha/user-frontend/ja/
---
src/locales/ja/translation.json | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/src/locales/ja/translation.json b/src/locales/ja/translation.json
index 0967ef4..d8d00bf 100644
--- a/src/locales/ja/translation.json
+++ b/src/locales/ja/translation.json
@@ -1 +1,27 @@
-{}
+{
+ "overview": "概要",
+ "nezha": "ナタモニタリング",
+ "dashboard": "ダッシュボード",
+ "login": "ログイン",
+ "online": "オンライン",
+ "offline": "オフライン",
+ "whereTheTimeIs": "現在の時刻",
+ "refreshing": "リフレッシュ",
+ "info": {
+ "websocketConnecting": "WebSocketを接続中",
+ "websocketConnected": "WebSocketを接続済み",
+ "websocketDisconnected": "WebSocketが切断された",
+ "processing": "処理中..."
+ },
+ "serverOverview": {
+ "totalServers": "サーバー総数",
+ "onlineServers": "オンラインサーバー",
+ "offlineServers": "オフラインサーバー",
+ "speed": "速度",
+ "network": "ネットワーク"
+ },
+ "map": {
+ "Distributions": "サーバーの場所",
+ "Regions": "地域"
+ }
+}
From 7821ce113111b5cc6412e38a8e8c1a0f6fc54932 Mon Sep 17 00:00:00 2001
From: hamster1963 <1410514192@qq.com>
Date: Sun, 12 Jul 2026 00:41:56 +0800
Subject: [PATCH 56/64] feat: enhance server handling and add empty state
messaging in Server component
---
scripts/mock-nezha-server.js | 47 ++++++++++++++++-----------
src/context/websocket-provider.tsx | 26 ++++++++++++++-
src/locales/de/translation.json | 4 ++-
src/locales/en/translation.json | 4 ++-
src/locales/es/translation.json | 4 ++-
src/locales/ru/translation.json | 4 ++-
src/locales/ta/translation.json | 4 ++-
src/locales/zh-CN/translation.json | 4 ++-
src/locales/zh-TW/translation.json | 4 ++-
src/pages/Server.tsx | 50 +++++++++++++++++++++++------
src/test/context/providers.test.tsx | 49 +++++++++++++++++++++++++---
src/test/pages/Server.test.tsx | 39 ++++++++++++++++++++++
12 files changed, 199 insertions(+), 40 deletions(-)
diff --git a/scripts/mock-nezha-server.js b/scripts/mock-nezha-server.js
index 44f0b33..1edd80a 100644
--- a/scripts/mock-nezha-server.js
+++ b/scripts/mock-nezha-server.js
@@ -114,11 +114,16 @@ function updateServerMetrics() {
}
function websocketPayload() {
- return JSON.stringify({
- now: Date.now(),
- online: onlineCount,
- servers,
- });
+ const payload = { now: Date.now() };
+
+ if (onlineCount > 0) {
+ payload.online = onlineCount;
+ }
+ if (servers.length > 0) {
+ payload.servers = servers;
+ }
+
+ return JSON.stringify(payload);
}
function jsonResponse(response, data) {
@@ -130,7 +135,7 @@ function jsonResponse(response, data) {
response.end(JSON.stringify(data));
}
-const serverGroups = [
+const populatedServerGroups = [
{
group: {
id: 1,
@@ -166,6 +171,7 @@ const serverGroups = [
.map((server) => server.id),
},
];
+const serverGroups = serverCount === 0 ? [] : populatedServerGroups;
const serviceHistory = Array.from({ length: 30 }, (_, index) => ({
up: 95 + (index % 6),
@@ -173,6 +179,22 @@ const serviceHistory = Array.from({ length: 30 }, (_, index) => ({
delay: 20 + index * 3,
}));
+const services =
+ serverCount === 0
+ ? {}
+ : {
+ mock_http: {
+ service_name: "Mock HTTP",
+ current_up: 1,
+ current_down: 0,
+ total_up: 2999,
+ total_down: 1,
+ delay: serviceHistory.map((item) => item.delay),
+ up: serviceHistory.map((item) => item.up),
+ down: serviceHistory.map((item) => item.down),
+ },
+ };
+
const httpServer = http.createServer((request, response) => {
const requestUrl = new URL(
request.url || "/",
@@ -213,18 +235,7 @@ const httpServer = http.createServer((request, response) => {
jsonResponse(response, {
success: true,
data: {
- services: {
- mock_http: {
- service_name: "Mock HTTP",
- current_up: 1,
- current_down: 0,
- total_up: 2999,
- total_down: 1,
- delay: serviceHistory.map((item) => item.delay),
- up: serviceHistory.map((item) => item.up),
- down: serviceHistory.map((item) => item.down),
- },
- },
+ services,
cycle_transfer_stats: {},
},
});
diff --git a/src/context/websocket-provider.tsx b/src/context/websocket-provider.tsx
index 55c77c1..73e72b1 100644
--- a/src/context/websocket-provider.tsx
+++ b/src/context/websocket-provider.tsx
@@ -11,6 +11,30 @@ interface WebSocketProviderProps {
children: React.ReactNode;
}
+type RawNezhaWebsocketResponse = Omit<
+ Partial,
+ "servers"
+> & {
+ servers?: unknown;
+};
+
+function normalizeWebSocketResponse(data: unknown): NezhaWebsocketResponse {
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
+ throw new TypeError("WebSocket message must be an object");
+ }
+
+ const response = data as RawNezhaWebsocketResponse;
+ if (typeof response.now !== "number" || !Number.isFinite(response.now)) {
+ throw new TypeError("WebSocket message must include a finite now value");
+ }
+
+ return {
+ ...response,
+ now: response.now,
+ servers: Array.isArray(response.servers) ? response.servers : [],
+ };
+}
+
export const WebSocketProvider: React.FC = ({
url,
children,
@@ -92,7 +116,7 @@ export const WebSocketProvider: React.FC = ({
throw new Error("WebSocket message data must be a string");
}
- const newData = JSON.parse(event.data) as NezhaWebsocketResponse;
+ const newData = normalizeWebSocketResponse(JSON.parse(event.data));
setLastData(newData);
// 更新历史消息,保持最新的30条记录
setMessageHistory((prev) => {
diff --git a/src/locales/de/translation.json b/src/locales/de/translation.json
index 53afe08..2612943 100644
--- a/src/locales/de/translation.json
+++ b/src/locales/de/translation.json
@@ -83,7 +83,9 @@
"websocketConnecting": "WebSocket verbindet",
"websocketConnected": "WebSocket verbunden",
"websocketDisconnected": "WebSocket getrennt",
- "processing": "Verarbeiten..."
+ "processing": "Verarbeiten...",
+ "noServers": "Keine Server verfügbar",
+ "noMatchingServers": "Keine Server entsprechen den aktuellen Filtern"
},
"tabSwitch": {
"Network": "Netzwerk",
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index e70a163..fa6c67f 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -11,7 +11,9 @@
"websocketConnecting": "WebSocket connecting",
"websocketConnected": "WebSocket connected",
"websocketDisconnected": "WebSocket disconnected",
- "processing": "Processing..."
+ "processing": "Processing...",
+ "noServers": "No servers available",
+ "noMatchingServers": "No servers match the current filters"
},
"serverOverview": {
"totalServers": "Total Servers",
diff --git a/src/locales/es/translation.json b/src/locales/es/translation.json
index ce4081b..cd9eebc 100644
--- a/src/locales/es/translation.json
+++ b/src/locales/es/translation.json
@@ -127,7 +127,9 @@
"websocketConnecting": "Conexión WebSocket",
"websocketDisconnected": "WebSocket desconectado",
"websocketConnected": "WebSocket conectado",
- "processing": "Procesando..."
+ "processing": "Procesando...",
+ "noServers": "No hay servidores disponibles",
+ "noMatchingServers": "Ningún servidor coincide con los filtros actuales"
},
"NoResults": "No se encontraron resultados.",
"refreshing": "Actualizando",
diff --git a/src/locales/ru/translation.json b/src/locales/ru/translation.json
index 9f8b279..4d8d247 100644
--- a/src/locales/ru/translation.json
+++ b/src/locales/ru/translation.json
@@ -53,7 +53,9 @@
"websocketConnecting": "WebSocket подключение",
"websocketConnected": "WebSocket подключен",
"websocketDisconnected": "WebSocket отключен",
- "processing": "Обработка..."
+ "processing": "Обработка...",
+ "noServers": "Нет доступных серверов",
+ "noMatchingServers": "Нет серверов, соответствующих текущим фильтрам"
},
"cycleTransfer": {
"nextUpdate": "следующее обновление",
diff --git a/src/locales/ta/translation.json b/src/locales/ta/translation.json
index 96fc37b..5378064 100644
--- a/src/locales/ta/translation.json
+++ b/src/locales/ta/translation.json
@@ -23,7 +23,9 @@
"websocketConnecting": "வெப்சாக்கெட் இணைத்தல்",
"websocketConnected": "வெப்சாக்கெட் இணைக்கப்பட்டுள்ளது",
"websocketDisconnected": "வெப்சாக்கெட் துண்டிக்கப்பட்டது",
- "processing": "செயலாக்கம் ..."
+ "processing": "செயலாக்கம் ...",
+ "noServers": "சேவையகங்கள் எதுவும் இல்லை",
+ "noMatchingServers": "தற்போதைய வடிப்பான்களுடன் பொருந்தும் சேவையகங்கள் எதுவும் இல்லை"
},
"serverOverview": {
"totalServers": "மொத்த சேவையகங்கள்",
diff --git a/src/locales/zh-CN/translation.json b/src/locales/zh-CN/translation.json
index 6605c2e..04b967a 100644
--- a/src/locales/zh-CN/translation.json
+++ b/src/locales/zh-CN/translation.json
@@ -11,7 +11,9 @@
"websocketConnecting": "WebSocket 连接中",
"websocketConnected": "WebSocket 连接成功",
"websocketDisconnected": "WebSocket 连接断开",
- "processing": "处理中..."
+ "processing": "处理中...",
+ "noServers": "暂无服务器",
+ "noMatchingServers": "没有符合当前筛选条件的服务器"
},
"serverOverview": {
"totalServers": "服务器总数",
diff --git a/src/locales/zh-TW/translation.json b/src/locales/zh-TW/translation.json
index 7a54f10..00dec72 100644
--- a/src/locales/zh-TW/translation.json
+++ b/src/locales/zh-TW/translation.json
@@ -11,7 +11,9 @@
"websocketConnecting": "WebSocket 連線中",
"websocketConnected": "WebSocket 連線成功",
"websocketDisconnected": "WebSocket 連線中斷",
- "processing": "處理中..."
+ "processing": "處理中...",
+ "noServers": "暫無伺服器",
+ "noMatchingServers": "沒有符合目前篩選條件的伺服器"
},
"serverOverview": {
"totalServers": "總伺服器",
diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx
index c73c895..a81b53f 100644
--- a/src/pages/Server.tsx
+++ b/src/pages/Server.tsx
@@ -4,6 +4,7 @@ import {
ArrowUpIcon,
ChartBarSquareIcon,
MapIcon,
+ ServerStackIcon,
ViewColumnsIcon,
} from "@heroicons/react/20/solid";
import { useQuery } from "@tanstack/react-query";
@@ -72,6 +73,25 @@ function BackendErrorState({ error }: { error: unknown }) {
);
}
+function ServerEmptyState({ filtered = false }: { filtered?: boolean }) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {t(filtered ? "info.noMatchingServers" : "info.noServers")}
+
+
+ );
+}
+
export default function Servers({
backendError,
}: {
@@ -409,6 +429,8 @@ export default function Servers({
);
}
+ const hasServers = nezhaWsData.servers.length > 0;
+
return (
-
+
- {showMap === "1" && (
-
+ )}
+ {hasServers && showServices === "1" && (
+
+ )}
+ {!hasServers ? (
+
+ ) : filteredServers.length > 0 ? (
+
+ ) : (
+
)}
- {showServices === "1" &&
}
-
);
}
diff --git a/src/test/context/providers.test.tsx b/src/test/context/providers.test.tsx
index cf4feb3..4df4e69 100644
--- a/src/test/context/providers.test.tsx
+++ b/src/test/context/providers.test.tsx
@@ -132,7 +132,10 @@ function WebSocketProbe() {
{connected ? "connected" : "disconnected"}
{lastData?.servers[0]?.name ?? "none"}
-
{messageHistory.length}
+
{messageHistory.length}
+
+ {messageHistory.reduce((total, item) => total + item.servers.length, 0)}
+
{needReconnect ? "needs-reconnect" : "stable"}