diff --git a/honk/Makefile b/honk/Makefile
index 4cd2b195d..3a51d1508 100644
--- a/honk/Makefile
+++ b/honk/Makefile
@@ -3,16 +3,16 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=honk
-PKG_VERSION:=0.0.1_beta81
-PKG_RELEASE:=1
+PKG_VERSION:=0.0.1_beta82
+PKG_RELEASE:=2
# Raw upstream release tag. It keeps the dots in qualifiers (e.g. v0.0.1.beta.49)
# because that is what the GitHub release asset name uses.
-HONK_RELEASE_TAG:=v0.0.1.beta.81
+HONK_RELEASE_TAG:=v0.0.1.beta.82
# SHA256 of each release tarball, kept in sync by scripts/update_honk_version.sh.
-HONK_HASH_X86_64:=88e5c3b29200c6ad729cc89636e14a452d974108cd08852c9c1e44074d23e10e
-HONK_HASH_AARCH64:=b160a3c8674556222b2b29ce6c975bc346f7ce3cddeb049474c6ca9e0a8191a6
+HONK_HASH_X86_64:=075db4ebb3dd1b51fb59c8e4c3de5853bd837f5f5ca5fd0ef7698b574f8f9a88
+HONK_HASH_AARCH64:=6b66319bda2110d075e8f2788d728fdf75ca36dffdb3884a192803a34a529c59
PKG_LICENSE:=AGPL-3.0-only
PKG_LICENSE_FILE:=LICENSE
@@ -89,6 +89,7 @@ define Package/honk/install
$(INSTALL_CONF) $(CURDIR)/files/config.d/node.dae $(1)/etc/honk/config.d/node.dae
$(INSTALL_CONF) $(CURDIR)/files/config.d/route.dae $(1)/etc/honk/config.d/route.dae
$(INSTALL_CONF) $(CURDIR)/files/config.d/dns.dae $(1)/etc/honk/config.d/dns.dae
+ $(INSTALL_CONF) $(CURDIR)/files/config.d/api.dae $(1)/etc/honk/config.d/api.dae
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) $(CURDIR)/files/honk.config $(1)/etc/config/honk
diff --git a/honk/files/config.d/api.dae b/honk/files/config.d/api.dae
new file mode 100644
index 000000000..b7af276bb
--- /dev/null
+++ b/honk/files/config.d/api.dae
@@ -0,0 +1,14 @@
+# api.dae
+# Configure API access for HONK dashboards and controllers.
+
+experimental {
+ native_api {
+ enabled: true
+ listen: '0.0.0.0:9527'
+ secret: 'honk114514'
+ ui: '/etc/honk/dashboard'
+ config_write: true
+ geosite_download_url: 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/release/geosite.dat'
+ geoip_download_url: 'https://raw.githubusercontent.com/QiuSimons/geoip-moedove/refs/heads/main/geoip.dat'
+ }
+}
diff --git a/honk/files/config.d/dns.dae b/honk/files/config.d/dns.dae
index 8693bfd37..6c3f1a730 100644
--- a/honk/files/config.d/dns.dae
+++ b/honk/files/config.d/dns.dae
@@ -5,7 +5,7 @@ dns {
#ipversion_prefer: 4
upstream {
local: 'udp://127.0.0.1:53' -> direct
- remote: 'tcp+udp://dns.google:53'
+ remote: 'tcp+udp://one.one.one.one:53'
}
routing {
request {
diff --git a/honk/files/config.dae b/honk/files/config.dae
index 4115010bb..0cfcde79e 100644
--- a/honk/files/config.dae
+++ b/honk/files/config.dae
@@ -22,21 +22,11 @@ global {
udp_check_dns: 'dns.google.com:53', '8.8.8.8', '2001:4860:4860::8888'
}
-# using for enable experimental features
-# native-api, clash-api, cache-file
+# API access (native_api / clash_api) is configured separately in config.d/api.dae
+# to allow web dashboard configuration without locking the config as read-only.
+#
+# Optional cache-file configuration:
#experimental {
-# native_api {
-# enabled: true
-# listen: '0.0.0.0:9527'
-# secret: 'honk'
-# ui: '/etc/honk/dashboard'
-# }
-# clash_api {
-# external_controller: '0.0.0.0:9090'
-# external_ui: '/etc/honk/zashboard'
-# secret: ''
-# default_mode: 'Rule'
-# }
# cache_file {
# enabled: true
# path: '/etc/honk/cache.db'
diff --git a/honk/files/honk.init b/honk/files/honk.init
index 0e6789b52..040156769 100644
--- a/honk/files/honk.init
+++ b/honk/files/honk.init
@@ -17,8 +17,9 @@ HONK_NETNS_PATH="/run/netns/$HONK_NETNS_NAME"
RESOLV_HONK="/tmp/resolv.conf.honk"
set_chmod_640() {
- mkdir -p /etc/honk/config.d
- chmod -R 640 /etc/honk/ 2>/dev/null || true
+ mkdir -p /etc/honk/config.d /etc/honk/state
+ chmod -R u=rwX,go= /etc/honk 2>/dev/null || true
+ chmod 700 /etc/honk /etc/honk/config.d /etc/honk/state 2>/dev/null || true
}
cleanup_netns() {
diff --git a/linkease-common-bin/Makefile b/linkease-common-bin/Makefile
index b28d56b6e..7978f56d5 100644
--- a/linkease-common-bin/Makefile
+++ b/linkease-common-bin/Makefile
@@ -12,7 +12,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease-common-bin
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
-PKG_RELEASE:=40
+PKG_RELEASE:=41
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
-PKG_SOURCE_VERSION:=9d3701bbe8fa141bd5b8293fd19651a8c1704050
+PKG_SOURCE_VERSION:=6a7d4c0d89d4e2bbcd8ba6558719353e91846255
PKG_SOURCE:=linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-common-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
diff --git a/linkease/Makefile b/linkease/Makefile
index 60d051051..4b0349de7 100644
--- a/linkease/Makefile
+++ b/linkease/Makefile
@@ -12,7 +12,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkease
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=1.7.5
-PKG_RELEASE:=43
+PKG_RELEASE:=44
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -28,7 +28,7 @@ else ifeq ($(ARCH),mipsel)
ARCH_HEXCODE=1b0c
endif
-PKG_SOURCE_VERSION:=9d3701bbe8fa141bd5b8293fd19651a8c1704050
+PKG_SOURCE_VERSION:=6a7d4c0d89d4e2bbcd8ba6558719353e91846255
PKG_SOURCE:=linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkease-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-bin-$(PKG_SOURCE_DATE)-linux-$(PKG_ARCH_LINKEASE)
diff --git a/linkeasefull/Makefile b/linkeasefull/Makefile
index a5b1ae673..f93a7b751 100644
--- a/linkeasefull/Makefile
+++ b/linkeasefull/Makefile
@@ -11,7 +11,7 @@ PKG_ARCH_LINKEASE:=$(ARCH)
PKG_NAME:=linkeasefull
# use PKG_SOURCE_DATE instead of PKG_VERSION for compitable
PKG_SOURCE_DATE:=3.0.22
-PKG_RELEASE:=42
+PKG_RELEASE:=43
ARCH_HEXCODE:=
ifeq ($(ARCH),x86_64)
@@ -24,7 +24,7 @@ LINKEASE_RUNTIME_ARCH:=arm64
PKG_HASH:=skip
endif
-PKG_SOURCE_VERSION:=9d3701bbe8fa141bd5b8293fd19651a8c1704050
+PKG_SOURCE_VERSION:=6a7d4c0d89d4e2bbcd8ba6558719353e91846255
PKG_SOURCE:=linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH).tar.gz
PKG_SOURCE_URL:=https://github.com/istoreos/istoreos-app-hub/releases/download/linkeasefull-runtime-v$(PKG_SOURCE_DATE)/
PKG_BUILD_DIR:=$(BUILD_DIR)/linkease-runtime-$(PKG_SOURCE_DATE)-linux-$(LINKEASE_RUNTIME_ARCH)
diff --git a/luci-app-adguardhome/.official_channel b/luci-app-adguardhome/.official_channel
index d7025695e..8ab67f2e7 100644
--- a/luci-app-adguardhome/.official_channel
+++ b/luci-app-adguardhome/.official_channel
@@ -1 +1 @@
-release
+snapshot
diff --git a/luci-app-adguardhome/.official_json_version b/luci-app-adguardhome/.official_json_version
index 0abf5391a..7a8654020 100644
--- a/luci-app-adguardhome/.official_json_version
+++ b/luci-app-adguardhome/.official_json_version
@@ -1 +1 @@
-26.268.33051~dd3d1cb
+26.270.72820~0818828
diff --git a/luci-app-agentflow/Makefile b/luci-app-agentflow/Makefile
index 66b117e65..51de1232d 100644
--- a/luci-app-agentflow/Makefile
+++ b/luci-app-agentflow/Makefile
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=AgentFlow
PKG_VERSION:=1.0.1
-PKG_RELEASE:=9
+PKG_RELEASE:=10
LUCI_DEPENDS:=+agentflow +luci-compat +luci-lib-taskd +luci-lib-linkeaseauth +linkease-app-entry
LUCI_MINIFY_CSS:=0
LUCI_MINIFY_JS:=0
diff --git a/luci-app-agentflow/tests/test_agentflow_luci_open_contract.py b/luci-app-agentflow/tests/test_agentflow_luci_open_contract.py
index e907bc893..ec1c84b80 100644
--- a/luci-app-agentflow/tests/test_agentflow_luci_open_contract.py
+++ b/luci-app-agentflow/tests/test_agentflow_luci_open_contract.py
@@ -1,9 +1,13 @@
+import json
from pathlib import Path
import unittest
APP_DIR = Path(__file__).resolve().parents[1]
-META_MAKEFILE = APP_DIR.parent / "app-meta-agentflow/Makefile"
+AGENTFLOW_DIR = APP_DIR.parent
+META_DIR = AGENTFLOW_DIR / "app-meta-agentflow"
+META_MAKEFILE = META_DIR / "Makefile"
+RUNTIME_DIR = AGENTFLOW_DIR / "agentflow"
class AgentFlowLuciOpenContractTest(unittest.TestCase):
@@ -18,7 +22,7 @@ class AgentFlowLuciOpenContractTest(unittest.TestCase):
self.assertIn("+luci-lib-linkeaseauth", makefile)
self.assertIn("+linkease-app-entry", makefile)
- self.assertIn("PKG_RELEASE:=3", meta)
+ self.assertIn("PKG_RELEASE:=2", meta)
self.assertIn("META_LUCI_ENTRY:=/cgi-bin/luci/admin/services/agentflow", meta)
self.assertIn('entry({"admin", "services", "agentflow", "open"}', controller)
self.assertIn("open.sysauth = false", controller)
@@ -33,6 +37,50 @@ class AgentFlowLuciOpenContractTest(unittest.TestCase):
self.assertIn('url("admin/services/agentflow/open")', status)
self.assertNotIn('window.location.hostname + ":" + st.port', status)
+ def test_app_meta_autoconfigures_agentflow_and_exposes_management_entry(self):
+ meta = META_MAKEFILE.read_text(encoding="utf-8")
+ config = (META_DIR / "config.sh").read_text(encoding="utf-8")
+ entry = (META_DIR / "entry.sh").read_text(encoding="utf-8")
+
+ self.assertIn("META_AUTOCONF:=path enable", meta)
+ self.assertIn('[ -n "$ISTORE_CONF_DIR" ] || exit 1', config)
+ self.assertIn('data_dir="$ISTORE_CONF_DIR/AgentFlow"', config)
+ self.assertIn('set agentflow.@agentflow[0].enabled="$enabled"', config)
+ self.assertIn('set agentflow.@agentflow[0].data_dir="$data_dir"', config)
+ self.assertIn('ISTORE_DONT_START', config)
+ self.assertIn('if [ "$enabled" = "1" ]; then', config)
+ self.assertIn('/etc/init.d/agentflow restart', config)
+ self.assertIn('/etc/init.d/agentflow stop || true', config)
+ self.assertNotIn('/etc/init.d/agentflow restart || true', config)
+
+ self.assertIn('json_add_string "app" "agentflow"', entry)
+ self.assertIn('json_add_boolean "docker" "0"', entry)
+ self.assertIn('pidof agentflow', entry)
+ self.assertIn('json_add_string "web" ":${port}${base_path}"', entry)
+ self.assertIn(
+ 'json_add_string "href" "/cgi-bin/luci/admin/services/agentflow"',
+ entry,
+ )
+ self.assertIn('/etc/init.d/agentflow start', entry)
+ self.assertIn('/etc/init.d/agentflow stop', entry)
+ self.assertNotIn("linkease_apps/open", entry)
+
+ def test_app_meta_and_desktop_icons_have_single_owners(self):
+ manifest = json.loads(
+ (RUNTIME_DIR / "files/agentflow-plugin.json").read_text(encoding="utf-8")
+ )
+ self.assertEqual(manifest["id"], "agentflow")
+ self.assertEqual(manifest["icon"], "logo.svg")
+ self.assertEqual(manifest["staticRoot"], "/usr/share/agentflow/www")
+ self.assertTrue((RUNTIME_DIR / "files/www/logo.svg").is_file())
+
+ meta_logo = META_DIR / "logo.png"
+ self.assertTrue(meta_logo.is_file())
+ self.assertTrue(meta_logo.read_bytes().startswith(b"\x89PNG\r\n\x1a\n"))
+ self.assertFalse(
+ (META_DIR / "root/usr/share/linkeasefull/desktop-apps.d").exists(),
+ "agentflow runtime already owns the desktop manifest",
+ )
if __name__ == "__main__":
unittest.main()
diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js
index 2608ee75f..8ec433993 100644
--- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js
+++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js
@@ -56,6 +56,14 @@ const congestion_controller = [
['bbr', _('bbr')],
];
+const ipstack_congestion_controller = [
+ ['', _('Keep default')],
+ ['cubic', _('cubic')],
+ ['reno', _('reno')],
+ ['bbr', _('bbr')],
+ ['bbr3', _('bbr3')],
+];
+
const bbr_profiles = [
['', _('Keep default')],
['standard', _('Standard')],
@@ -2149,6 +2157,7 @@ return baseclass.extend({
monospacefonts,
checkurls,
congestion_controller,
+ ipstack_congestion_controller,
bbr_profiles,
stunserver,
dashrepos,
diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js
index 21ac8a278..60838d05c 100644
--- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js
+++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/global.js
@@ -512,13 +512,13 @@ return view.extend({
so = ss.option(form.RichListValue, 'tun_stack', _('Stack'),
_('Tun stack.'));
- so.value('system', _('System'), _('Less compatibility and sometimes better performance.'));
+ so.value('mips', _('mihomo IP stack (MIPS)'));
if (features.with_gvisor) {
so.value('gvisor', _('gVisor'), _('Based on google/gvisor.'));
so.value('mixed', _('Mixed'), _('Mixed system TCP stack and gVisor UDP stack.'));
}
- so.value('mips', _('mihomo IP stack (MIPS)'));
- so.default = 'system';
+ so.value('system', _('System'), _('Less compatibility and sometimes better performance.'));
+ so.default = 'mips';
so.rmempty = false;
so = ss.option(form.Value, 'tun_mtu', _('MTU'));
@@ -545,6 +545,13 @@ return view.extend({
so = ss.option(form.Flag, 'tun_disable_icmp_forwarding', _('Disable ICMP Forwarding'),
_('Prevent ICMP loopback issues in some cases. Ping will not show real delay.'));
so.default = so.enabled;
+
+ so = ss.option(form.ListValue, 'tun_congestion_controller', _('Congestion controller'));
+ so.default = hm.ipstack_congestion_controller[0][0];
+ hm.ipstack_congestion_controller.forEach((res) => {
+ so.value.apply(so, res);
+ })
+ so.depends('tun_stack', 'mips');
/* Inbound END */
/* TLS START */
diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js
index 9e771fa38..8d93872f7 100644
--- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js
+++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js
@@ -1200,17 +1200,18 @@ return view.extend({
so = ss.taboption('field_general', form.ListValue, 'ipstack', _('IP stack'));
so.value('', _('Keep default'));
so.value('auto', _('Auto'));
- so.value('gvisor', _('gVisor'));
so.value('mips', _('mihomo IP stack (MIPS)'));
+ if (features.with_gvisor) {
+ so.value('gvisor', _('gVisor'));
+ }
so.depends({type: /^(zerotier|wireguard|masque|openvpn)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'ipstack_congestion_controller', _('IP stack') + ': ' + _('Congestion controller'));
- so.value('', _('Keep default'));
- so.value('cubic', _('cubic'));
- so.value('reno', _('reno'));
- so.value('bbr', _('bbr'));
- so.value('bbr3', _('bbr3'));
+ so.default = hm.ipstack_congestion_controller[0][0];
+ hm.ipstack_congestion_controller.forEach((res) => {
+ so.value.apply(so, res);
+ })
so.depends({ipstack: /^(auto|mips)$/}); // not empty not gvisor
so.modalonly = true;
diff --git a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc
index 66b7fb15f..67e6f66f1 100644
--- a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc
+++ b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc
@@ -403,6 +403,7 @@ if (match(proxy_mode, /tun/))
"udp-timeout": durationToSecond(uci.get(uciconf, uciinbound, 'tun_udp_timeout')) || 300,
"endpoint-independent-nat": strToBool(uci.get(uciconf, uciinbound, 'tun_endpoint_independent_nat')),
"disable-icmp-forwarding": (uci.get(uciconf, uciinbound, 'tun_disable_icmp_forwarding') === '0') ? false : true,
+ "congestion-controller": uci.get(uciconf, uciinbound, 'tun_congestion_controller'),
"auto-detect-interface": true
};
/* Inbound END */
diff --git a/luci-app-forcedata/Makefile b/luci-app-forcedata/Makefile
index f7304e307..bf733591f 100644
--- a/luci-app-forcedata/Makefile
+++ b/luci-app-forcedata/Makefile
@@ -2,7 +2,7 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-20230829
-PKG_RELEASE:=1
+PKG_RELEASE:=2
PKG_MAINTAINER:=forcedata
LUCI_TITLE:=LuCI support for forcedata
diff --git a/luci-app-forcedata/README.en.md b/luci-app-forcedata/README.en.md
new file mode 100644
index 000000000..495667c4f
--- /dev/null
+++ b/luci-app-forcedata/README.en.md
@@ -0,0 +1,69 @@
+[简体中文](README.md) | [English](README.en.md)
+
+# luci-app-forcedata
+
+A LuCI management plugin for the "ForceData (原力云)" edge-computing client on OpenWrt / iStoreOS.
+
+
+
+
+
+## 📖 Introduction
+
+ForceData (YuanLiYun) is an edge-computing / bandwidth-sharing platform: you run its client on your own device and share idle bandwidth online for a certain monthly cash reward. This plugin moves the whole deployment into LuCI: after installation it automatically downloads and starts the forcecloud client, keeps it alive with minute-level checks and self-updates, and provides a service status page with a QR-code binding entry in the router admin UI.
+
+It targets owners of OpenWrt / iStoreOS soft routers and TV boxes who want to run ForceData without touching the command line. The plugin is built on the iStore app framework (`luci-lib-taskd` + istorec management script), so it behaves like other iStoreOS apps.
+
+## ✨ Features
+
+- LuCI web UI under "Services → Forcedata", showing live service status
+- Automatically generates an 18-digit numeric UID on first use, stored in `/etc/config/forcedata` (do not change it, or deployment breaks)
+- One-click install / upgrade of the forcecloud client, auto-selecting x86_64 / aarch64 builds with MD5 verification
+- crontab-based self-check every minute: restarts the process when it dies, and skips updates when the root partition is 100% full
+- Pushes DingTalk robot alerts when the client restarts unexpectedly or multiple probes start on one host
+- The status page renders a binding QR code to link the device via the "ForceData" WeChat mini program
+- The management script supports install / upgrade / rm / start / stop / restart / status sub-commands
+
+## 🛠 Tech Stack
+
+- LuCI (Lua) + iStore/taskd app framework, depends on `luci-lib-taskd`, package arch `all`
+- busybox ash shell management script
+- Page QR code rendered with qrcode.min.js
+
+## 🚀 Quick Start
+
+1. Build: copy this repo into the `package/` directory of an OpenWrt/LeDE source tree, select `LuCI → Applications → luci-app-forcedata` in `make menuconfig`, then build the ipk and install it on the router.
+2. On first installation, uci-defaults registers a crontab keep-alive job that runs every minute.
+3. Log in to LuCI, open "Services → Forcedata", confirm the UID, and wait for the status to become Running.
+4. Click "Running, click to show QR" to render the QR code, then scan it with the "ForceData" WeChat mini program to bind the device. See the [official guide](https://docs.qq.com/doc/DZXNFWWtKbHN4UHFD) (Chinese).
+
+You can also manage it over SSH:
+
+```sh
+sh /usr/libexec/istorec/forcedata.sh install # Install / start the client
+sh /usr/libexec/istorec/forcedata.sh status # Show running status
+sh /usr/libexec/istorec/forcedata.sh rm # Stop the process and clean /usr/local/forcecloud
+```
+
+## 📁 Directory Structure
+
+```
+luci-app-forcedata/
+├── luasrc/ # LuCI controller, CBI config page, status view
+├── po/zh-cn/ # Simplified Chinese language pack
+├── root/
+│ ├── etc/config/forcedata # UCI config (uid)
+│ ├── etc/uci-defaults/luci-app-forcedata # Registers crontab on first install
+│ ├── usr/libexec/istorec/forcedata.sh # Install / keep-alive / update script
+│ └── www/luci-static/forcedata/ # QR-code JS and mini-program image
+└── Makefile
+```
+
+## 🔗 Links
+
+- [ForceData official site](http://www.forcedata.cn) (Chinese)
+- [Mini-program binding guide](https://docs.qq.com/doc/DZXNFWWtKbHN4UHFD) (Chinese)
+
+## 📄 License
+
+No LICENSE file is included in this repo (the Makefile lists the maintainer as forcedata). For learning and research only.
diff --git a/luci-app-forcedata/README.md b/luci-app-forcedata/README.md
new file mode 100644
index 000000000..517852263
--- /dev/null
+++ b/luci-app-forcedata/README.md
@@ -0,0 +1,69 @@
+[简体中文](README.md) | [English](README.en.md)
+
+# luci-app-forcedata
+
+OpenWrt / iStoreOS 平台的「原力云(Forcedata)」边缘计算客户端 LuCI 管理插件。
+
+
+
+
+
+## 📖 项目介绍
+
+原力云是一个边缘计算 / 共享带宽平台:在自家设备上运行它的客户端,在线共享闲置带宽,每月可获取一定的现金回报。本插件把整套部署流程搬进 LuCI:安装后自动下载并拉起 forcecloud 客户端,分钟级保活与自更新,并在路由器管理页提供运行状态与扫码绑定入口。
+
+适合已经刷了 OpenWrt / iStoreOS 的软路由、盒子玩家,不敲命令行即可挂机跑原力云。插件基于 iStore 应用框架(`luci-lib-taskd` + istorec 管理脚本)开发,与 iStoreOS 上其他应用的使用方式一致。
+
+## ✨ 功能特性
+
+- LuCI 图形界面:菜单位置「服务 → Forcedata(原力云)」,实时展示服务运行状态
+- 首次使用自动生成 18 位数字 UID,保存在 `/etc/config/forcedata`(请勿修改,否则影响部署)
+- 一键安装 / 升级 forcecloud 客户端,自动区分 x86_64 / aarch64 架构,下载包做 MD5 校验
+- 通过 crontab 每分钟自检:进程掉线自动拉起,根分区使用率 100% 时自动跳过更新
+- 客户端异常重启、同一主机重复启动探针时,通过钉钉机器人推送报警
+- 状态页可生成绑定二维码,用「原力云」微信小程序扫码绑定设备
+- 管理脚本支持 install / upgrade / rm / start / stop / restart / status 子命令
+
+## 🛠 技术栈
+
+- LuCI(Lua)+ iStore/taskd 应用框架,依赖 `luci-lib-taskd`,包架构 all
+- busybox ash Shell 管理脚本
+- 页面二维码基于 qrcode.min.js 生成
+
+## 🚀 快速开始
+
+1. 编译安装:把本仓库放进 OpenWrt/LeDE 源码的 `package/` 目录,`make menuconfig` 选中 `LuCI → Applications → luci-app-forcedata`,编译出 ipk 后安装到路由器;
+2. 首次安装时 uci-defaults 会自动注册每分钟执行一次的 crontab 保活任务;
+3. 登录 LuCI 进入「服务 → Forcedata」,确认 UID 后等待状态变为 Running;
+4. 点击「Running, click to show QR」生成二维码,用「原力云」微信小程序扫码绑定设备,详见[官方教程](https://docs.qq.com/doc/DZXNFWWtKbHN4UHFD)。
+
+也可以在 SSH 里手动管理:
+
+```sh
+sh /usr/libexec/istorec/forcedata.sh install # 安装 / 拉起客户端
+sh /usr/libexec/istorec/forcedata.sh status # 查看运行状态
+sh /usr/libexec/istorec/forcedata.sh rm # 停止进程并清理 /usr/local/forcecloud
+```
+
+## 📁 目录结构
+
+```
+luci-app-forcedata/
+├── luasrc/ # LuCI 控制器、CBI 配置页、状态视图
+├── po/zh-cn/ # 简体中文语言包
+├── root/
+│ ├── etc/config/forcedata # UCI 配置(uid)
+│ ├── etc/uci-defaults/luci-app-forcedata # 首次安装注册 crontab
+│ ├── usr/libexec/istorec/forcedata.sh # 安装 / 保活 / 更新脚本
+│ └── www/luci-static/forcedata/ # 二维码 JS 与小程序码图片
+└── Makefile
+```
+
+## 🔗 相关链接
+
+- [原力云官网](http://www.forcedata.cn)
+- [小程序扫码绑定教程](https://docs.qq.com/doc/DZXNFWWtKbHN4UHFD)
+
+## 📄 License
+
+本仓库未附带 LICENSE 文件(Makefile 中标注维护者为 forcedata),仅供学习研究。
diff --git a/luci-app-fwlive/Makefile b/luci-app-fwlive/Makefile
index 0a17b6372..2a79c9520 100644
--- a/luci-app-fwlive/Makefile
+++ b/luci-app-fwlive/Makefile
@@ -12,7 +12,7 @@ LUCI_DEPENDS:=+luci-base +logd +jsonfilter +coreutils-timeout
LUCI_PKGARCH:=all
PKG_VERSION:=0.1.46
-PKG_RELEASE:=46
+PKG_RELEASE:=47
# Reproducible build: honor SOURCE_DATE_EPOCH from the build environment (set by docker-sdk.sh / CI).
ifdef SOURCE_DATE_EPOCH
diff --git a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js
index 94f68e10d..19302e36a 100644
--- a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js
+++ b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js
@@ -169,24 +169,33 @@ return baseclass.extend({
};
const evalNode = function (node) {
- if (node.and) {
+ const keys = Object.keys(node);
+ if (keys.length !== 1)
+ throw new Error(
+ 'CLASSIFY_SPEC node must have exactly one key: ' + JSON.stringify(node)
+ );
+ const key = keys[0];
+ if (key === 'and') {
+ if (!Array.isArray(node.and))
+ throw new Error('CLASSIFY_SPEC and node must be an array');
for (let i = 0; i < node.and.length; i++) {
if (!evalNode(node.and[i])) return false;
}
return true;
}
- if (node.or) {
+ if (key === 'or') {
+ if (!Array.isArray(node.or))
+ throw new Error('CLASSIFY_SPEC or node must be an array');
for (let i = 0; i < node.or.length; i++) {
if (evalNode(node.or[i])) return true;
}
return false;
}
- const keys = Object.keys(node);
- for (let i = 0; i < keys.length; i++) {
- const k = keys[i];
- if (pred[k]) return pred[k](node);
- }
- return false;
+ if (!Object.prototype.hasOwnProperty.call(pred, key))
+ throw new Error(
+ 'unrecognised CLASSIFY_SPEC predicate node: ' + JSON.stringify(node)
+ );
+ return pred[key](node);
};
for (let i = 0; i < this.CLASSIFY_SPEC.rules.length; i++) {
diff --git a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js
index 423073894..b6b1b804f 100644
--- a/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js
+++ b/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js
@@ -320,7 +320,7 @@ function rowClass(index, row, state, callbacks) {
.join(' ');
}
-function buildRow(row, index, state, columns, callbacks) {
+function buildRow(row, index, state, columns, callbacks, key) {
const cells = [];
for (let c = 0; c < columns.length; c++)
cells.push(buildColumnCell(columns[c], row, state, callbacks));
@@ -334,7 +334,7 @@ function buildRow(row, index, state, columns, callbacks) {
cells
);
tr._fwliveRowId = String(row.id);
- tr._fwliveRowKey = rowRenderKey(row, state, columns);
+ tr._fwliveRowKey = key === undefined ? rowRenderKey(row, state, columns) : key;
return tr;
}
@@ -398,7 +398,7 @@ function renderRows(host, state, callbacks) {
const id = String(row.id);
const key = rowRenderKey(row, state, columns);
let tr = existingRows.get(id);
- if (!tr || tr._fwliveRowKey !== key) tr = buildRow(row, i, state, columns, callbacks);
+ if (!tr || tr._fwliveRowKey !== key) tr = buildRow(row, i, state, columns, callbacks, key);
else tr.setAttribute('class', rowClass(i, row, state, callbacks));
tr._fwliveRowId = id;
tr._fwliveRowKey = key;
diff --git a/luci-app-fwlive/po/templates/luci-app-fwlive.pot b/luci-app-fwlive/po/templates/luci-app-fwlive.pot
index 929fa5576..a08449ccb 100644
--- a/luci-app-fwlive/po/templates/luci-app-fwlive.pot
+++ b/luci-app-fwlive/po/templates/luci-app-fwlive.pot
@@ -15,7 +15,7 @@ msgid ""
"messages returned"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:493
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:502
msgid "%s: %s"
msgstr ""
@@ -27,7 +27,7 @@ msgstr ""
msgid "Accessible (teal/orange)"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:353
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:362
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:37
msgid "Action"
msgstr ""
@@ -183,7 +183,7 @@ msgstr ""
msgid "Degraded — sampling (slow poll RTT; cadence reduced)."
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:357
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:366
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:45
msgid "Destination"
msgstr ""
@@ -192,7 +192,7 @@ msgstr ""
msgid "Destination IP contains (! to exclude)"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:359
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:368
msgid "Destination port"
msgstr ""
@@ -361,7 +361,7 @@ msgstr ""
msgid "Installation is incomplete. Reinstall luci-app-fwlive."
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:354
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:363
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:39
msgid "Interface"
msgstr ""
@@ -497,7 +497,7 @@ msgstr ""
msgid "Paused"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:355
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:364
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:43
msgid "Proto"
msgstr ""
@@ -555,7 +555,7 @@ msgstr ""
msgid "SPort"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:352
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:361
msgid "Search"
msgstr ""
@@ -596,7 +596,7 @@ msgstr ""
msgid "Simple"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:356
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:365
#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/table.js:44
msgid "Source"
msgstr ""
@@ -605,7 +605,7 @@ msgstr ""
msgid "Source IP contains (! to exclude)"
msgstr ""
-#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:358
+#: openwrt-feed/luci-app-fwlive/htdocs/luci-static/resources/fwlive/log.js:367
msgid "Source port"
msgstr ""
diff --git a/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh b/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh
index 125e0c3d5..e2e41b91e 100755
--- a/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh
+++ b/luci-app-fwlive/root/usr/libexec/fwlive-adaptive-cap.sh
@@ -12,9 +12,11 @@
# Lock: sibling ${FWLIVE_ADAPTIVE_LOCK_FILE:-$STATE.lock} — never the JSON
# inode (atomic mv replaces that inode; locking it would not serialize writers).
# Lock covers only short update — never held across ubus/filter work.
-# Hot-path budget: ≤1 flock exec per update (release by closing the fd when the
-# subshell exits — no flock -u). /proc/uptime + state I/O via shell builtins/
-# redirects (no sed/cat/jsonfilter on the adaptive path). Fail-open on missing
+# Hot-path budget: ≤1 flock exec and 2 find execs per successful update
+# (directory safety checked before lock open and before the state write).
+# Release flock by closing the fd when the subshell exits (no flock -u).
+# /proc/uptime + state I/O use shell builtins/redirects (no sed/cat/jsonfilter
+# on the adaptive path). Fail-open on missing
# flock, lock busy, or corrupt state. Fail-closed if the lock file cannot be
# opened (skip the write; do not record unlocked). Lock-busy ⇒ unlocked
# last-writer-wins is acceptable (state stays one valid JSON line; ordering
diff --git a/luci-app-fwlive/root/usr/libexec/rpcd/fwlive b/luci-app-fwlive/root/usr/libexec/rpcd/fwlive
index fba93a7b8..0c5d6458c 100755
--- a/luci-app-fwlive/root/usr/libexec/rpcd/fwlive
+++ b/luci-app-fwlive/root/usr/libexec/rpcd/fwlive
@@ -253,7 +253,7 @@ run_with_timeout() {
fi
done
[ "$peer" = 1 ] || break
- "$busybox_bin" sleep 0.1
+ "$busybox_bin" sleep 0.1 || "$busybox_bin" sleep 1 || exit 125
done
exit "$status"
' fwlive-timeout "$FWLIVE_TIMEOUT_BIN" "$secs" \
@@ -1220,6 +1220,7 @@ run_selftest() {
got=$(printf '%s\n' "log prefix \"fwlive${_tab}tabbed\" comment \"!fw4: TabRule\"" | nft_dump_fields)
OUT=''
_map_keys=0
+ _map_lines=0
_map_overflow=''
map_from_nft_stream all <.tar.gz` holds the source of the honk commit they were built from and `HONK-SOURCE.txt` names that commit; `SHA256SUMS` lists every release asset except itself. The builds are attached until honk publishes a release with the native API. (#109, #117)
+- Sign-in is a full page instead of a dialog over an empty window, with its own language menu and theme toggle. From 1024 pixels wide, a panel beside the form shows a construction scene that becomes a small Flappy Duck game when pressed. The form keeps working if the scene fails to load, and the scene is a still picture when reduced motion is requested. (#107, #114, #115)
+- The public demo opens on the sign-in page with its account filled in: user name `demo`, password `demo`. (#107)
+- The setup guide is a separate documentation site in English, Simplified Chinese and Traditional Chinese, maintained in [Zakkaus/doona-docs](https://github.com/Zakkaus/doona-docs). Sign-in and Settings > About link to it; the sign-in hint for a backend without the native API and the read-only outbound mode help open its troubleshooting sections. (#100)
+- The documentation site has step-by-step installation pages for Debian or Ubuntu, Fedora or RHEL, Arch Linux, Gentoo, OpenWrt and other systems, and follows the layout of the React Spectrum docs. Its search ranks titles first and works from the keyboard, the 404 page is in the reader's language, and Chinese pages use the Spectrum CJK type scale. Colours are correct in Safari 17.0 to 17.4, and links into doona's source work when the pages are read on GitHub. The pages are shared under CC BY 4.0, and the header links to the demo. (Zakkaus/doona-docs#1, #2, #3, #6, #11, #13, #14)
+- Help buttons explain unclear states and terms on Overview, Connections, Configuration, Rules, Policies, DNS, Events, Logs and Settings. (#98)
+- Overview lists the features that are off in a full-width card, one row per cause. Where one applies, a row explains the cause, gives the configuration lines that turn the feature on, or links to the documentation or Settings. The rule list, validation and closing connections are listed when the backend lacks them. The count on Activity links to the card. (#102)
+- A disabled action says why in a line beside its buttons, visible at every width, where before the reason was only in a tooltip that touch does not open, or missing. This covers Configuration, Activity, Policies, Rules, DNS, Nodes and Settings, and the dialogs for new rules, subscriptions and nodes. Screen readers read the line as the button's description. (#97, #127, #130, #133)
+- Connections can collapse and expand each group, or all groups at once, while the list is grouped. (#93)
+- On Events and Logs, pressing a row, or Enter or Space on it, shows its full text below the table, so text cut on a phone can be read; pressing the row again hides it. (#105)
+- The demo shows its error states when opened with `?scenario=faults`; `?scenario=` returns to the healthy demo. (#103)
+
+### Changed
+
+- The demo behaves as a healthy honk: it seeds no failures, and switching the outbound mode works. (#103)
+- The Overview header and the Activity status add a degraded or failed datapath to the engine state, in the matching tone. The Overview header links to the Datapath card. (#102)
+- Backend features on Overview lists only the features that are on. (#102)
+- Configuration shows each source's path once. A read-only source has one badge naming the reason (generated, subscription, read-only, contains secrets, redacted or text not returned) and no Validate button; when configuration writes are off, help beside the badge says how to turn them on. Every source with text has one line saying what it is and what can be done with it, and all source editors start at the same height. (#101)
+- A writable source is edited in place, without an Edit button. Typing, pasting or tapping in a read-only source shows one notice with the reason. (#101)
+- When a save finds that the file changed on disk, the source card, the modules and the quick setup show an alert and wait until the draft is kept over the change or discarded; previously, the draft was applied to the changed file without warning. A module draft carries over on its own when the change is outside its section. (#118)
+- Read-only code editors show no caret or current-line highlight; the line a source was opened at keeps a marker. (#97)
+- The must switch in the new-rule dialog reads Lock this outbound, with a line explaining what a locked outbound skips. (#91)
+- The outbound mode card and the Arrange review label their button Apply and reload, as Configuration does, since all three write the configuration and reload it. (#126)
+- Below 600 pixels wide, tables keep every column at its minimum width and scroll sideways, instead of dropping columns until the rest fit. Wider screens drop columns as before. (#128)
+- On Policies, a large node group lays out its tiles like a small group: the same columns, tile width and edges, with room left for the scrollbar. (#125)
+- The busiest-host tile on Connections takes two shares of its row. A host that still does not fit keeps its end visible and shows the full name on hover, focus or tap. (#99)
+- When a subscription refresh leaves the datapath degraded, the notice says that new connections proxied through userspace are refused and points to Overview. (#98)
+- The Chinese token sign-in heading and missing-token message use formal wording. (#107)
+- README screenshots are rendered by the documentation site on each deploy and are no longer stored in the repository. (Zakkaus/doona-docs#6)
+- NOTICE, `REUSE.toml`, the READMEs and the `OFL.txt` shipped with the fonts name Adobe as the copyright holder of Noto Sans TC and SC. The documentation site credits Adobe for the Spectrum icons, fonts and design. (#122, Zakkaus/doona-docs#12)
+
+### Fixed
+
+- Errors with the reused codes `invalid_request`, `unsupported_value` and `state_conflict` keep the backend's own message beside the summary. (#94)
+- A backend that never answers no longer leaves a page loading. API reads fail when the headers, or the next part of the body, take more than 15 seconds to arrive, and writes when they take more than 30; the event and log streams keep their own limit. Sign-in and sign-out time out the same way. After a read timeout, Retry fetches the data again. A write timeout says the change may have been applied and asks for a reload before trying again. (#104, #118)
+- Apply and reload is disabled when a refetch makes the open source read-only. Undo after Cancel no longer restores the discarded edits. (#101, #106)
+- The must switch in the new-rule dialog aligns with the outbound picker. (#90)
+- A connection opened by its link unfolds its collapsed group, and so does a selected connection that moves into another folded group. Outbound groups no longer unfold when the language changes, and an outbound named like a built-in label keeps its own group. (#93, #118)
+- When an ordinary rule precedes the must rules in the routing block, doona's refusal to switch the outbound mode says to move the must rules to the top and names the rule. (#103)
+- Trace field errors wait until a field is filled. Chrome no longer reports `apple-mobile-web-app-capable` as deprecated. (#103)
+- Help buttons and status lights align with the centre of their text. (#98)
+- Logs and the flow distribution say when the configuration forbids their recorder. Test all no longer blames TCP probe support when it is unavailable for another reason. (#98)
+- The minimum password length applies only to the administrator password created at setup, not to signing in. (#107)
+- A failed suspend or resume shows its translated message again (`lifecycle_failed`). (#115)
+- Overview no longer gives honk's causes and fixes for resources an older backend leaves out of its capabilities; they are listed as not provided by the build. When another engine gives no reason, a read-only main configuration no longer claims one. (#118, #132)
+- A read-only source is labelled as containing secrets only when its text defines a `native_api` or `clash_api` block; otherwise it shows as read-only. (#118)
+- The health-check URL dialog sends only the fields that were edited and offers the check settings that the group's `mutable_config` lists. A save no longer replaces a change another client made to the same field: it fails as a conflict and the dialog stays open. (#106, #118, #132)
+- The new-source dialog warns that a path is not included only when no loaded file includes it, and resolves include patterns from the main configuration's directory, as honk does. (#118, #131)
+- A geodata update whose result cannot be confirmed is shown as unknown, not as failed. (#106)
+- A new source whose read-back fails stays created, and a late result no longer reaches a reopened new-file dialog. A selected diagnostic stays selected across polls. In the demo, a new source whose name has a space, a non-ASCII character or `?` opens once created. (#106)
+- The demo refuses source writes over honk's size limits, a second create of the same path and a create past the source limit, as honk does. Demo sign-in works over plain HTTP on a LAN address, where browsers do not provide `crypto.randomUUID`. (#118, #124, #131)
+- The DNS device filter error appears under its field and is read with it by screen readers. The DNS log's time column fits relative times. (#105, #106)
+- The note on the Arrange tab of Policies no longer mentions an Add menu on each row; it points to Add to group below the list and to Review and apply. (#111)
+
+### For contributors
+
+- CONTRIBUTING describes the architecture and the import allow-lists, and lint enforces the engine boundary. (#123)
+- `tools/honk-commit.txt` pins the honk commit a release bundles; the release workflow fails unless honk's `debug` release, its target and its source tag name that commit. (#117)
+- The API contract is pinned at api-standardize 3640713. (#116)
+- The store, the configuration page, the engine explanations, the sign-in outcomes and the connection test were split into smaller modules, and unused code and duplicate strings were removed, without changing behaviour. (#108, #119, #120, #121, #126, #129)
+
## [0.1.0-beta.7] - 2026-09-27
### Added
@@ -253,6 +318,7 @@ This changelog follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
- Keep table columns and action cells visible and prevent cards and controls from overflowing.
+[0.1.0-beta.8]: https://github.com/Zakkaus/doona/compare/v0.1.0-beta.7...v0.1.0-beta.8
[0.1.0-beta.7]: https://github.com/Zakkaus/doona/compare/v0.1.0-beta.6...v0.1.0-beta.7
[0.1.0-beta.6]: https://github.com/Zakkaus/doona/compare/v0.1.0-beta.5...v0.1.0-beta.6
[0.1.0-beta.5]: https://github.com/Zakkaus/doona/compare/v0.1.0-beta.4...v0.1.0-beta.5
diff --git a/luci-app-honk/root/etc/honk/dashboard/NOTICE b/luci-app-honk/root/etc/honk/dashboard/NOTICE
index dd532b507..b9077d2cb 100644
--- a/luci-app-honk/root/etc/honk/dashboard/NOTICE
+++ b/luci-app-honk/root/etc/honk/dashboard/NOTICE
@@ -6,3 +6,9 @@ Licensed under the Apache License, Version 2.0:
https://www.apache.org/licenses/LICENSE-2.0
Source: https://github.com/adobe/react-spectrum
+Noto Sans TC and Noto Sans SC
+Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name
+'Source'.
+The fonts in public/fonts are the Google Fonts subsets of Noto Sans TC and SC
+from https://github.com/notofonts/noto-cjk.
+Licensed under the SIL Open Font License, Version 1.1; see public/fonts/OFL.txt.
diff --git a/luci-app-honk/root/etc/honk/dashboard/README.md b/luci-app-honk/root/etc/honk/dashboard/README.md
index bac52b402..51855d04f 100644
--- a/luci-app-honk/root/etc/honk/dashboard/README.md
+++ b/luci-app-honk/root/etc/honk/dashboard/README.md
@@ -1,32 +1,31 @@
-
-
-
-
+
# doona
**Web UI for the [daeuniverse](https://github.com/daeuniverse) engines: nodes, groups, rules and the configuration, from a browser.**
-English · [简体中文](README.zh-CN.md) · [繁體中文](README.zh-TW.md)
+**[Live demo](https://demo.daeuniverse.org/)** / **[Documentation](https://zakkaus.github.io/doona-docs/en/)**
-[Install](#install) • [First run](#first-run) • [Pages](#pages) • [Page tour](#page-tour) • [On a phone](#on-a-phone) • [Development](#development) • [Guide](docs/guide.md)
+English / [简体中文](README.zh-CN.md) / [繁體中文](README.zh-TW.md)
+
+[Install](#install) / [Pages](#pages) / [Page tour](#page-tour) / [On a phone](#on-a-phone) / [Development](#development)
doona is a static web UI for the native API the daeuniverse engines share: honk today, dae once it implements the same contract. The engine serves it itself or any web server does; it shows what the engine is doing and manages nodes, groups, routing rules and configuration files.
-[Try the demo with sample data](https://demo.daeuniverse.org/).
+[Try the demo with sample data](https://demo.daeuniverse.org/). To see the error states, open it with [`?scenario=faults`](https://demo.daeuniverse.org/?scenario=faults); `?scenario=` returns to the healthy demo.
-
+
Every palette
Eleven palettes support light and dark modes; Rosé Pine and Catppuccin include multiple dark flavours. Use the palette picker in the top bar.
-
+
@@ -34,12 +33,12 @@ Eleven palettes support light and dark modes; Rosé Pine and Catppuccin include
The activity page in four palettes. Select a palette and mode from the top bar.
-| Theme gallery | Light | Dark |
-| ------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------ |
-| Rosé Pine |  |  |
-| Catppuccin |  |  |
-| Nord |  |  |
-| Glass |  |  |
+| Theme gallery | Light | Dark |
+| ------------- | ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
+| Rosé Pine |  |  |
+| Catppuccin |  |  |
+| Nord |  |  |
+| Glass |  |  |
## Status
@@ -47,129 +46,88 @@ doona targets the native API implemented by honk's `feat/native-api` branch; tha
## Install
-Release archives (`doona-.tar.gz`, the optional `doona-fonts-.tar.gz` with Noto Sans TC and SC, and `SHA256SUMS`) are attached to tags on the [releases page](https://github.com/Zakkaus/doona/releases). Build from source as described under [Development](#development). Verify and extract the files into the directory the engine or web server will serve:
+doona needs honk's native API, which only the `debug` release of [Glassyiris/honk `feat/native-api`](https://github.com/Glassyiris/honk/tree/feat/native-api) provides so far. Release archives (`doona-.tar.gz`, the optional `doona-fonts-.tar.gz` with Noto Sans TC and SC, and `SHA256SUMS`) are attached to tags on the [releases page](https://github.com/Zakkaus/doona/releases). Extract them into the directory that honk's `native_api` block names in `ui`, and honk serves doona at `/ui/`.
-```sh
-VERSION=0.1.0-beta.7 # replace with the downloaded release version, without v
-sha256sum --ignore-missing -c SHA256SUMS
-sudo mkdir -p /usr/share/doona
-sudo tar -xzf "doona-${VERSION}.tar.gz" -C /usr/share/doona
-if [ -f "doona-fonts-${VERSION}.tar.gz" ]; then
- sudo tar -xzf "doona-fonts-${VERSION}.tar.gz" -C /usr/share/doona
-fi
-```
+From v0.1.0-beta.8 on, until honk publishes a release with the native API, each doona release also attaches prebuilt `honk-core-debug-[-stock].tar.gz` archives from that `debug` release, so no one needs to compile honk. `HONK-SOURCE.txt` names the honk commit they were built from, `honk-source-.tar.gz` holds that commit's source, and `SHA256SUMS` covers every release asset except itself. [Install honk](https://zakkaus.github.io/doona-docs/en/install.html#install) explains which archive fits a gateway.
-### Native API requirement
-
-**Required honk build:** doona needs the native API in [Glassyiris/honk `feat/native-api`](https://github.com/Glassyiris/honk/tree/feat/native-api). No tagged daeuniverse/honk release includes it yet. The `native_api` and `password_auth` keys may change before upstream release. A released honk returns 404 for `/api` and `/ui/`. The configuration below applies to that branch.
-
-honk's native API is opt-in. Point `ui` at the extracted files and honk serves them at `/ui/`, same-origin with the API:
-
-```dae
-experimental {
- native_api {
- enabled: true
- listen: '127.0.0.1:9527'
- password_auth: true
- ui: '/usr/share/doona'
- }
-}
-```
-
-Keep this block in its own include (`include { api.dae }`) so the main file stays editable from the configuration page. For scripts and automation, use `secret: ''` instead of `password_auth: true`. Requirements, serving from another web server or a reverse proxy, and the distribution packages are in the [guide](docs/guide.md#install).
-
-## First run
-
-Open `/ui/` on the engine host. On a first visit doona asks the origin it was served from for `/api` and saves the engine as a backend. In password mode, the locked sign-in dialog offers first-time setup to create the administrator; complete setup from a loopback or private-network client, then sign in with the username and password. Served from elsewhere, or to reach another engine, open Settings and enter the server root.
-
-In token mode, doona asks for the token. Enter it in Settings with the server root, or use a pairing link such as `/ui/#/settings?api=http://router:9527&token=…` to fill the form; doona removes the token from the address bar on load.
-
-The activity page then shows the running engine. Add a subscription or paste share links on Nodes, pick or pin members on Policies, add rules on Rules, and edit, validate and reload the sources on Configuration. Every write goes through the engine with the hash doona read the source at, and a failed reload keeps the previous generation active. The [guide](docs/guide.md#first-run) walks through each page.
+The [documentation](https://zakkaus.github.io/doona-docs/en/) covers the requirements, installing honk and doona, an example configuration, the first sign-in, checking each feature and troubleshooting.
## Pages
-
+
-| Page | Shows |
-| ------------- | --------------------------------------------------------------------------------------------------------------- |
-| Activity | Outbound mode, traffic and memory, active connections, node latency, outbound usage, top clients, notifications |
-| Overview | Engine and eBPF state, process CPU, traffic counters, backend capabilities, the status as JSON |
-| Connections | Live connections with source, destination, rule, chain, traffic and transfer rates; close one or all |
-| DNS | Queries with their answers, the cache, the log; a flush |
-| Policies | Groups, their members and health; selection, pinning, probing, editing and health-check URLs |
-| Rules | A routing tree from rules or devices through outbounds to nodes, the rule list with hits, the flow log, a trace |
-| Nodes | Subscriptions and their refresh interval, inline nodes, add and remove, probe and join a group |
-| Configuration | Create and edit source files, diagnostics, validation, quick setup and export |
-| Events, Logs | The backend event stream; the log stream with filters, pause and export |
-| Settings | Backends, runtime settings and backend actions, language, appearance, palette and notification placement |
+| Page | Shows |
+| ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
+| Activity | Outbound mode, traffic and memory, active connections, node latency, outbound usage, top clients, notifications |
+| Overview | Engine and eBPF state, process CPU, traffic counters, backend capabilities and the features that are off, the status as JSON |
+| Connections | Live connections with source, destination, rule, chain, traffic and transfer rates; fold groups, close one or all |
+| DNS | Queries with their answers, the cache, the log; a flush |
+| Policies | Groups, their members and health; selection, pinning, probing, editing and health-check URLs |
+| Rules | A routing tree from rules or devices through outbounds to nodes, the rule list with hits, the flow log, a trace |
+| Nodes | Subscriptions and their refresh interval, inline nodes, add and remove, probe and join a group |
+| Configuration | Create source files and edit them in place, diagnostics, validation, quick setup and export |
+| Events, Logs | The backend event stream; the log stream with filters, pause and export |
+| Settings | Backends, runtime settings and backend actions, language, appearance, palette and notification placement |
-A page is marked unavailable only when every resource it needs is unavailable. `Ctrl K` searches pages, connections, nodes, groups, rules and sources from anywhere. Which resources each page needs, and where doona keeps its own settings, are in the [guide](docs/guide.md#pages).
+A page is marked unavailable only when every resource it needs is unavailable. `Ctrl K` searches pages, connections, nodes, groups, rules and sources from anywhere. Which resources each page needs, and where doona keeps its own settings, are on the [features page](https://zakkaus.github.io/doona-docs/en/features.html#pages). Help buttons beside unclear states and terms explain them.
-
+Sign-in is a page of its own with the language menu and scheme toggle. From 1024 pixels wide, a panel beside the form shows a construction scene; pressing it starts a Flappy Duck game. The demo fills in the user name `demo` and the password `demo`.
+
+
## Page tour
### Arranging groups
-On the Arrange tab of Policies, drag a node or a subscription from the list on the right onto a group to add it. The Add menu on each row and keyboard dragging do the same.
+On the Arrange tab of Policies, drag a node or a subscription from the list on the right onto a group to add it. Keyboard dragging does the same, and Add to group below the list adds the selected rows to a group. The changes stay staged until you open Review and apply and press Apply.
-
+
### Traffic and connections
The Traffic tab of Connections plots each connection's upload against its download, coloured by outbound; select a point to open that connection. The Connections tab groups live connections by device or by outbound, filters them by protocol and outbound, and exports them as CSV.
-
+
-
+
### DNS
The Statistics tab shows the median and P95 resolution time, the cache hit rate and the failure rate. The charts below place each upstream's lookups on a latency scale and count how the queries ended.
-
+
### Log activity
Above the log list, a heatmap counts records per level over time. A level's row header sets the minimum level the list shows.
-
+
### Routing map
The routing map on Rules follows traffic from rules, or from devices, through outbounds to nodes. Point at or select a rule, outbound or node to highlight the paths through it.
-
+
### Node latency
-The Latency tab of Nodes plots each node's latest latency, moving average and average of the last 10 measurements. A switch groups the nodes by policy group or by protocol; unavailable nodes appear under their group.
+The Latency tab of Nodes plots each node's latest latency, and its moving average and the average of the last 10 measurements when the backend reports them. A switch groups the nodes by policy group or by protocol; unavailable nodes appear under their group.
-
+
## On a phone
Below 1024 pixels wide, the side navigation becomes a bottom bar with four hubs: Overview, Traffic, Routing and Settings. A hub opens on the page last viewed in it during the session, and its pages sit in a row above the content. Language, theme, palette and wordmark move into the top bar's overflow menu, a submenu each.
-Tables drop the columns that do not fit, in a set order, and toolbars wrap onto more rows. On Overview, DNS and Logs, the first page action stays a button and the rest move into a menu.
+Below 600 pixels wide, tables keep every column and scroll sideways; on wider screens they drop the columns that do not fit, in a set order. Toolbars wrap onto more rows. On Events and Logs, press a row to read its full text below the table. On Overview, DNS and Logs, the first page action stays a button and the rest move into a menu.
Over HTTPS or on localhost, doona installs as an app. In Chrome and Edge, the About card in Settings offers Install as an app. Safari has no install prompt, so the card shows the steps instead. On iPhone and iPad, tap Share, then Add to Home Screen. In Safari 26 on macOS, choose File > Add to Dock.
-
+
## Development
-```sh
-pnpm install --frozen-lockfile
-pnpm build # writes dist/
-pnpm check # types, lint, translations, formatting, unit tests, generated API types
-pnpm check:size # gzip budgets for the dist/ build
-pnpm e2e:install --with-deps # once, for the browser tests
-pnpm e2e # rebuild, then test against the mock at the root and under /ui/
-pnpm package # release/doona-.tar.gz, doona-fonts-.tar.gz, SHA256SUMS
-```
-
-`pnpm dev` serves the mock on Vite's dev server. The live-backend test run, the performance and screenshot tools, the source layout and the contract pin are described in the [guide](docs/guide.md#development); see [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request. Its [Translations](CONTRIBUTING.md#translations) section covers correcting a translation and proposing a language.
+The build, test and packaging commands, the source layout and the contract pin are on the [development page](https://zakkaus.github.io/doona-docs/en/development.html). See [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request.
## Support
@@ -177,4 +135,4 @@ Report bugs and ask questions in the [issues](https://github.com/Zakkaus/doona/i
## License and credits
-[GPL-3.0-only](LICENSE). Noto Sans TC and SC are under the [Open Font License](public/fonts/OFL.txt); [NOTICE](NOTICE) credits the Adobe Spectrum icons (Apache-2.0). The duck is the maintainer's own artwork.
+[GPL-3.0-only](LICENSE). Noto Sans TC and SC are copyright Adobe and licensed under the [Open Font License](public/fonts/OFL.txt); [NOTICE](NOTICE) credits the Adobe Spectrum icons (Apache-2.0). The duck is the maintainer's own artwork.
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-C-LVMOvQ.js b/luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-90AzAQje.js
similarity index 74%
rename from luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-C-LVMOvQ.js
rename to luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-90AzAQje.js
index fa2c13a23..0ab7c5df5 100644
--- a/luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-C-LVMOvQ.js
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/ActionGroup-90AzAQje.js
@@ -1 +1 @@
-import{j as s}from"./vendor-react-Bf71BWbF.js";import{u as o,dP as c,dQ as p,dR as x,dS as m,B as u}from"./index-zQjLFfuj.js";const r=({action:n})=>s.jsxs(u,{isDisabled:n.isDisabled,isPending:n.isPending,onPress:n.onAction,children:[n.icon,n.label]});function b({actions:n,overflowMode:d="collapse"}){const l=o();if(d==="wrap")return s.jsx(s.Fragment,{children:n.map(e=>s.jsx(r,{action:e},e.id))});const[a,...i]=n;return a?s.jsxs(s.Fragment,{children:[s.jsx(r,{action:a}),i.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"rp-wide-only",children:i.map(e=>s.jsx(r,{action:e},e.id))}),s.jsx("span",{className:"rp-narrow-only",children:s.jsx(c,{chevron:!1,label:l("ui.moreActions"),content:s.jsx(x,{"aria-label":l("ui.moreActions"),disabledKeys:i.filter(e=>e.isDisabled||e.isPending).map(e=>e.id),onAction:e=>i.find(t=>t.id===e)?.onAction(),children:i.map(e=>s.jsx(m,{id:e.id,className:"rp-item plain",textValue:e.label,children:e.label},e.id))}),children:s.jsx(p,{})})})]})]}):null}export{b as A};
+import{j as s}from"./vendor-react-Bf71BWbF.js";import{u as o,e2 as c,e3 as p,e4 as x,e5 as m,B as u}from"./index-CXHBmSa5.js";const r=({action:n})=>s.jsxs(u,{isDisabled:n.isDisabled,isPending:n.isPending,onPress:n.onAction,children:[n.icon,n.label]});function b({actions:n,overflowMode:t="collapse"}){const l=o();if(t==="wrap")return s.jsx(s.Fragment,{children:n.map(e=>s.jsx(r,{action:e},e.id))});const[a,...i]=n;return a?s.jsxs(s.Fragment,{children:[s.jsx(r,{action:a}),i.length>0&&s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"rp-wide-only",children:i.map(e=>s.jsx(r,{action:e},e.id))}),s.jsx("span",{className:"rp-narrow-only",children:s.jsx(c,{chevron:!1,label:l("ui.moreActions"),content:s.jsx(x,{"aria-label":l("ui.moreActions"),disabledKeys:i.filter(e=>e.isDisabled||e.isPending).map(e=>e.id),onAction:e=>i.find(d=>d.id===e)?.onAction(),children:i.map(e=>s.jsx(m,{id:e.id,className:"rp-item plain",textValue:e.label,children:e.label},e.id))}),children:s.jsx(p,{})})})]})]}):null}export{b as A};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-DSsJ-CRu.js b/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-DSsJ-CRu.js
deleted file mode 100644
index e443feccf..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-DSsJ-CRu.js
+++ /dev/null
@@ -1 +0,0 @@
-import{j as r}from"./vendor-react-Bf71BWbF.js";import{bd as t}from"./index-zQjLFfuj.js";function o({className:a,...s}){return r.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:t("rp-icon",a),...s,children:r.jsx("path",{fill:"currentColor",d:"M10 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17m0 15.5a7 7 0 1 1 0-14 7 7 0 0 1 0 14m3.75-7.75h-3v-3a.75.75 0 0 0-1.5 0v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5"})})}export{o as A};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-Db3HxlxQ.js b/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-Db3HxlxQ.js
new file mode 100644
index 000000000..811b214d0
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/AddCircle-Db3HxlxQ.js
@@ -0,0 +1 @@
+import{j as r}from"./vendor-react-Bf71BWbF.js";import{c as t}from"./index-CXHBmSa5.js";function o({className:a,...s}){return r.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:t("rp-icon",a),...s,children:r.jsx("path",{fill:"currentColor",d:"M10 1.5a8.5 8.5 0 1 0 0 17 8.5 8.5 0 0 0 0-17m0 15.5a7 7 0 1 1 0-14 7 7 0 0 1 0 14m3.75-7.75h-3v-3a.75.75 0 0 0-1.5 0v3h-3a.75.75 0 0 0 0 1.5h3v3a.75.75 0 0 0 1.5 0v-3h3a.75.75 0 0 0 0-1.5"})})}export{o as A};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-BPSqH5mH.js b/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-BPSqH5mH.js
deleted file mode 100644
index 6f55bc178..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-BPSqH5mH.js
+++ /dev/null
@@ -1 +0,0 @@
-import{r as u,j as l}from"./vendor-react-Bf71BWbF.js";import{u as ct,as as it,eq as rt,er as ut}from"./index-zQjLFfuj.js";import{u as ht,e as dt,v as H,C as xt,f as pt,n as ft,g as J}from"./layout-B3T-zLsm.js";import{G as mt,C as yt}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";const Mt=a=>{const o=Math.pow(10,Math.floor(Math.log10(a))),e=a/o;return([1,1.2,1.5,2,2.5,3,4,5,6,8,10].find(h=>e<=h)??10)*o},gt=a=>{const o=Math.pow(10,Math.floor(Math.log10(Math.max(a,1e-9)))),e=a/o;return(e<=1?.2:e<=2?.5:e<=5?1:2)*o},F=[30,60,120,300,600,900,1800,3600,7200,21600,43200,86400].map(a=>a*1e3);function kt(a,o){const e=o-a,s=F.find(c=>e/c<=6)??F[F.length-1],h=s>=864e5?new Date(o).getTimezoneOffset()*6e4:0,y=Math.ceil((a-h)/s)*s+h,x=[];for(let c=y;c<=o;c+=s)c-a>=e*.04&&o-c>=e*.04&&x.push(c);return{ticks:x,step:s}}function Q(a){const[o,e]=u.useState([]);return u.useLayoutEffect(()=>{const s=document.createElement("span");Object.assign(s.style,{position:"absolute",top:"-20000px",whiteSpace:"pre",fontSize:"11px"}),document.body.appendChild(s),e(a.map(y=>{s.textContent=y;const{width:x,height:c}=s.getBoundingClientRect();return{width:x,height:c}})),s.remove()},[a]),o}function zt({label:a,series:o,timestamps:e,fmt:s,locale:h,height:y=150,baseline:x="zero",window:c,fill:U}){const X=ct(),w=it(),A=u.useId(),[Y,L]=rt(Math.round,120),{tip:Z,showAt:_,hide:E}=ht(),[C,B]=u.useState(null),i=C&&C.indexM!==void 0&&g!==void 0?kt(M,g):void 0,[M,g]),D=p?p.step<6e4:I<180*1e3,N=p?p.step>=864e5:I>2160*60*1e3,G=u.useMemo(()=>new Intl.DateTimeFormat(h,N?{month:"numeric",day:"numeric"}:D?{hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}:{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[h,D,N]),{yDomain:K,yTicks:j}=u.useMemo(()=>{const t=o.flatMap(d=>d.values.filter(z=>z!==null));let n=0,r=Mt(Math.max(1,...t)*1.08);if(x==="auto"&&t.length){const d=Math.min(...t),z=Math.max(...t),b=gt(Math.max(z-d,z*.02,1));n=Math.max(0,Math.floor(d/b)*b-b),r=Math.ceil(z/b)*b+b}return{yDomain:[n,r],yTicks:x==="auto"?[n,(n+r)/2,r]:[r/2,r]}},[o,x]),P=u.useMemo(()=>{const t=e.length-1;return p?p.ticks:[...new Set((D?[0,Math.round(t/2),t]:[0,Math.round(t/3),Math.round(2*t/3),t]).map(n=>e[n]))]},[p,D,e]),O=u.useMemo(()=>M!==void 0&&g!==void 0?[M,g]:[Math.min(...e),Math.max(...e)],[M,g,e]),k=L?.width??0,S=L?.height??y,m=S-30,v=k-64,tt=[Math.min(O[0],...e),Math.max(O[1],...e)],f=t=>J(t,tt,[20,v]),T=t=>J(t,K,[m,8]),et={x:20,y:8,width:v-20,height:m-8},R=(t,n)=>B({index:t,y:n}),W=()=>{B(null),E()};u.useLayoutEffect(()=>{if(i===null){E();return}if(!o.some(t=>t.values[i]!=null)){E();return}_({x:f(e[i]),y:C?.y??(8+m)/2,width:k,bounds:et,label:ut(h).format(e[i]),lines:o.filter(t=>t.values[i]!=null).sort((t,n)=>t.labeln.label?1:0).map(t=>`${t.label}${X("ui.labelSeparator")}${s(t.values[i])}`)})});const $=dt(e.length,R,W),q=u.useMemo(()=>P.map(t=>G.format(t)),[P,G]),nt=u.useMemo(()=>j.map(s),[j,s]),ot=Q(q),st=Q(nt),lt=p?H(P.map(f),ot.map(t=>t.width),0,k,16,!0):P.map((t,n)=>({index:n,position:f(t)})),V=H(j.map(T),st.map(t=>t.height),0,S,5,!1),at=[...new Set([...V.map(t=>T(j[t.index])),8,m])];return l.jsx("div",{ref:Y,style:{height:y,width:"100%",flex:U?"1 1 auto":void 0,position:"relative"},onPointerLeave:$.onPointerLeave,children:e.length>0&&L&&l.jsxs(l.Fragment,{children:[l.jsx(xt,{tip:Z}),l.jsxs("svg",{className:"rp-activity-surface",width:k,height:S,viewBox:`0 0 ${k} ${S}`,style:{display:"block"},role:"application","aria-label":a,tabIndex:0,onFocus:$.onFocus,onBlur:$.onBlur,onKeyDown:$.onKeyDown,onPointerMove:t=>{const{x:n,y:r}=pt(t,t.currentTarget,{width:k,height:S});if(n<20||n>v||r<8||r>m){W();return}const d=ft(e.map(f),n);R(d,r)},children:[l.jsx("g",{className:"rp-area-grid",children:at.map(t=>l.jsx("line",{x1:20,x2:v,y1:t,y2:t,stroke:w["hl-med"],strokeDasharray:"2 4",fill:"none"},t))}),l.jsx("defs",{children:o.map((t,n)=>l.jsx(mt,{id:A+n,color:t.color},t.label))}),o.map((t,n)=>l.jsx(yt,{points:e.map((r,d)=>t.values[d]==null?null:{x:f(r),y:T(t.values[d])}),baseline:T(Math.max(0,K[0])),color:t.color,id:A+n,strokeWidth:2},t.label)),i!==null&&l.jsx("path",{d:`M${f(e[i])},8L${f(e[i])},${m}`,stroke:w.subtle,strokeDasharray:"3 3",fill:"none",pointerEvents:"none"}),l.jsx("g",{children:lt.map(({index:t,position:n})=>l.jsx("text",{x:n,y:m+8,fontSize:11,fill:w.subtle,textAnchor:"middle",children:l.jsx("tspan",{x:n,dy:"0.71em",children:q[t]})},t))}),l.jsx("g",{className:"rp-area-y-ticks",children:V.map(({index:t,position:n})=>l.jsx("text",{x:v+8,y:n,fontSize:11,fill:w.subtle,textAnchor:"start",children:l.jsx("tspan",{x:v+8,dy:"0.355em",children:s(j[t])})},t))}),i!==null&&o.map(t=>t.values[i]==null?null:l.jsx("circle",{cx:f(e[i]),cy:T(t.values[i]),r:4,fill:t.color,stroke:"#fff",strokeWidth:2},t.label))]})]})})}export{zt as AreaPlot};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-DtE4xcoZ.js b/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-DtE4xcoZ.js
new file mode 100644
index 000000000..8ce0a4c95
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/AreaChart-DtE4xcoZ.js
@@ -0,0 +1 @@
+import{r as u,j as a}from"./vendor-react-Bf71BWbF.js";import{u as ct,aB as it,eH as rt,eI as ut}from"./index-CXHBmSa5.js";import{u as ht,e as dt,v as q,C as xt,f as pt,n as ft,g as J}from"./layout-BRLew_nj.js";import{G as mt,C as yt}from"./AreaCurve-BriPYJva.js";import"./array-C0P64tl-.js";const Mt=l=>{const o=Math.pow(10,Math.floor(Math.log10(l))),e=l/o;return([1,1.2,1.5,2,2.5,3,4,5,6,8,10].find(h=>e<=h)??10)*o},gt=l=>{const o=Math.pow(10,Math.floor(Math.log10(Math.max(l,1e-9)))),e=l/o;return(e<=1?.2:e<=2?.5:e<=5?1:2)*o},B=[30,60,120,300,600,900,1800,3600,7200,21600,43200,86400].map(l=>l*1e3);function kt(l,o){const e=o-l,s=B.find(c=>e/c<=6)??B[B.length-1],h=s>=864e5?new Date(o).getTimezoneOffset()*6e4:0,y=Math.ceil((l-h)/s)*s+h,x=[];for(let c=y;c<=o;c+=s)c-l>=e*.04&&o-c>=e*.04&&x.push(c);return{ticks:x,step:s}}function Q(l){const[o,e]=u.useState([]);return u.useLayoutEffect(()=>{const s=document.createElement("span");Object.assign(s.style,{position:"absolute",top:"-20000px",whiteSpace:"pre",fontSize:"11px"}),document.body.appendChild(s),e(l.map(y=>{s.textContent=y;const{width:x,height:c}=s.getBoundingClientRect();return{width:x,height:c}})),s.remove()},[l]),o}function wt({label:l,series:o,timestamps:e,fmt:s,locale:h,height:y=150,baseline:x="zero",window:c,fill:U}){const X=ct(),C=it(),F=u.useId(),[Y,L]=rt(Math.round,120),{tip:Z,showAt:_,hide:E}=ht(),[z,I]=u.useState(null),i=z&&z.indexM!==void 0&&g!==void 0?kt(M,g):void 0,[M,g]),D=p?p.step<6e4:N<180*1e3,A=p?p.step>=864e5:N>2160*60*1e3,G=u.useMemo(()=>new Intl.DateTimeFormat(h,A?{month:"numeric",day:"numeric"}:D?{hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}:{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[h,D,A]),{yDomain:K,yTicks:j}=u.useMemo(()=>{const t=o.flatMap(d=>d.values.filter(w=>w!==null));let n=0,r=Mt(Math.max(1,...t)*1.08);if(x==="auto"&&t.length){const d=Math.min(...t),w=Math.max(...t),b=gt(Math.max(w-d,w*.02,1));n=Math.max(0,Math.floor(d/b)*b-b),r=Math.ceil(w/b)*b+b}return{yDomain:[n,r],yTicks:x==="auto"?[n,(n+r)/2,r]:[r/2,r]}},[o,x]),P=u.useMemo(()=>{const t=e.length-1;return p?p.ticks:[...new Set((D?[0,Math.round(t/2),t]:[0,Math.round(t/3),Math.round(2*t/3),t]).map(n=>e[n]))]},[p,D,e]),O=u.useMemo(()=>M!==void 0&&g!==void 0?[M,g]:[Math.min(...e),Math.max(...e)],[M,g,e]),k=L?.width??0,S=L?.height??y,m=S-30,v=k-64,tt=[Math.min(O[0],...e),Math.max(O[1],...e)],f=t=>J(t,tt,[20,v]),T=t=>J(t,K,[m,8]),et={x:20,y:8,width:v-20,height:m-8},R=(t,n)=>I({index:t,y:n}),W=()=>{I(null),E()};u.useLayoutEffect(()=>{if(i===null){E();return}if(!o.some(t=>t.values[i]!=null)){E();return}_({x:f(e[i]),y:z?.y??(8+m)/2,width:k,bounds:et,label:ut(h).format(e[i]),lines:o.filter(t=>t.values[i]!=null).sort((t,n)=>t.labeln.label?1:0).map(t=>`${t.label}${X("ui.labelSeparator")}${s(t.values[i])}`)})});const $=dt(e.length,R,W),H=u.useMemo(()=>P.map(t=>G.format(t)),[P,G]),nt=u.useMemo(()=>j.map(s),[j,s]),ot=Q(H),st=Q(nt),at=p?q(P.map(f),ot.map(t=>t.width),0,k,16,!0):P.map((t,n)=>({index:n,position:f(t)})),V=q(j.map(T),st.map(t=>t.height),0,S,5,!1),lt=[...new Set([...V.map(t=>T(j[t.index])),8,m])];return a.jsx("div",{ref:Y,style:{height:y,width:"100%",flex:U?"1 1 auto":void 0,position:"relative"},onPointerLeave:$.onPointerLeave,children:e.length>0&&L&&a.jsxs(a.Fragment,{children:[a.jsx(xt,{tip:Z}),a.jsxs("svg",{className:"rp-activity-surface",width:k,height:S,viewBox:`0 0 ${k} ${S}`,style:{display:"block"},role:"application","aria-label":l,tabIndex:0,onFocus:$.onFocus,onBlur:$.onBlur,onKeyDown:$.onKeyDown,onPointerMove:t=>{const{x:n,y:r}=pt(t,t.currentTarget,{width:k,height:S});if(n<20||n>v||r<8||r>m){W();return}const d=ft(e.map(f),n);R(d,r)},children:[a.jsx("g",{className:"rp-area-grid",children:lt.map(t=>a.jsx("line",{x1:20,x2:v,y1:t,y2:t,stroke:C["hl-med"],strokeDasharray:"2 4",fill:"none"},t))}),a.jsx("defs",{children:o.map((t,n)=>a.jsx(mt,{id:F+n,color:t.color},t.label))}),o.map((t,n)=>a.jsx(yt,{points:e.map((r,d)=>t.values[d]==null?null:{x:f(r),y:T(t.values[d])}),baseline:T(Math.max(0,K[0])),color:t.color,id:F+n,strokeWidth:2},t.label)),i!==null&&a.jsx("path",{d:`M${f(e[i])},8L${f(e[i])},${m}`,stroke:C.subtle,strokeDasharray:"3 3",fill:"none",pointerEvents:"none"}),a.jsx("g",{children:at.map(({index:t,position:n})=>a.jsx("text",{x:n,y:m+8,className:"rp-area-tick",fill:C.subtle,textAnchor:"middle",children:a.jsx("tspan",{x:n,dy:"0.71em",children:H[t]})},t))}),a.jsx("g",{className:"rp-area-y-ticks",children:V.map(({index:t,position:n})=>a.jsx("text",{x:v+8,y:n,className:"rp-area-tick",fill:C.subtle,textAnchor:"start",children:a.jsx("tspan",{x:v+8,dy:"0.355em",children:s(j[t])})},t))}),i!==null&&o.map(t=>t.values[i]==null?null:a.jsx("circle",{cx:f(e[i]),cy:T(t.values[i]),r:4,fill:t.color,stroke:"#fff",strokeWidth:2},t.label))]})]})})}export{wt as AreaPlot};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-Aggv2ZKG.js b/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-Aggv2ZKG.js
new file mode 100644
index 000000000..3edb3764f
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-Aggv2ZKG.js
@@ -0,0 +1,4 @@
+import{r as x,$ as _,a as St,j as f}from"./vendor-react-Bf71BWbF.js";import{eu as Pt,eN as Bt,eo as ae,bT as G,bR as M,eO as Qe,eP as et,eQ as It,bL as Re,el as F,em as re,en as Be,e7 as N,eA as tt,eR as At,eS as Ot,eT as Mt,bI as jt,bU as Nt,b$ as Rt,eU as Lt,c1 as Vt,c2 as Gt,bG as Ht,es as zt,c4 as Ut,bD as Xt,c6 as Yt,c8 as qt,c5 as _t,eV as Wt,eW as Jt,bE as ke,aJ as Zt,eE as Qt,eB as er,bQ as tr,eX as rt,eY as nt,eZ as oe,bF as rr,bB as at,e6 as nr,c as Ie,J as Ke,e_ as Le,d9 as ot,e$ as Ve,f0 as Ge,de as it,u as W,a5 as ar,a8 as or,a7 as He,aa as ir,cA as lr,dB as sr,b as ur,bb as ze,E as dr,j as cr,I as Q,af as lt,B as L,d5 as Ue,ac as st,T as ut,a as dt,aH as Xe,aC as pr,bx as fr,$ as de,L as gr,h as yr,by as mr,aG as hr,b1 as Dr,eF as br,eG as $r,f1 as vr,aE as Er,bj as xr,ae as ct,cG as wr}from"./index-CXHBmSa5.js";import{$ as Tr,a as kr}from"./Policies-wpHv6bOW.js";import{d as Kr}from"./Virtualizer--Vfl8O3n.js";import{$ as Cr}from"./ListLayout-CPapuywx.js";import{D as pt}from"./DaeCode-STEiRZuV.js";import{b as Fr,g as Sr}from"./policyText-CAFy3qpo.js";import{P as Pr}from"./PolicyPicker-DSSmYroN.js";import{$ as Br}from"./useFilter-DZ8TXqn_.js";import"./useGridSelectionCheckbox-BV96yL-N.js";var P=(function(e){return e[e.none=0]="none",e[e.cancel=0]="cancel",e[e.move=1]="move",e[e.copy=2]="copy",e[e.link=4]="link",e[e.all=7]="all",e})({});const ft={...P,copyMove:3,copyLink:6,linkMove:5,all:7,uninitialized:7},gt=yt(ft);gt[7]="all";const ee={none:"cancel",link:"link",copy:"copy",move:"move"},De=yt(ee);function yt(e){let t={};for(let r in e)t[e[r]]=r;return t}const Ir=new Set(["text/plain","text/uri-list","text/html"]),fe="application/vnd.react-aria.items+json",ge="application/octet-stream",Ae=new WeakMap,mt=Symbol();function Ar(e){let{id:t}=Ae.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function Or(e){let{ref:t}=Ae.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function z(e){let t=new Set;for(let r of e)for(let n of Object.keys(r))t.add(n);return t}function ht(e){return e||(e="virtual"),e==="pointer"&&(e="virtual"),e==="virtual"&&typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(pointer: coarse)").matches&&(e="touch"),e}function Oe(){return ht(Pt())}function Dt(){return ht(Bt())}function Ce(e,t){let r=new Map,n=!1,a=[];for(let o of t){let y=Object.keys(o);y.length>1&&(n=!0);let c={};for(let D of y){let v=r.get(D);v?n=!0:(v=[],r.set(D,v));let g=o[D];c[D]=g,v.push(g)}a.push(c)}for(let[o,y]of r)if(Ir.has(o)){let c=y.join(`
+`);e.items.add(c,o)}else e.items.add(y[0],o);if(n){let o=JSON.stringify(a);e.items.add(o,fe)}}class ie{constructor(t){this.types=new Set;let r=!1;for(let n of t.items)n.type!==fe&&(n.kind==="file"&&(r=!0),n.type?this.types.add(n.type):this.types.add(ge));this.includesUnknownTypes=!r&&t.types.includes("Files")}has(t){if(Array.isArray(t))return t.some(r=>this.has(r));if(this.includesUnknownTypes||t===mt&&this.types.has(ge)||t==="*/*")return!0;if(typeof t=="string"){if(t.endsWith("/*")){for(let r of this.types)if(r.startsWith(t.slice(0,-2)))return!0;return!1}return this.types.has(t)}return!1}}function bt(e){let t=[];if(!e)return t;let r=!1;if(e.types.includes(fe))try{let n=e.getData(fe),a=JSON.parse(n);for(let o of a)t.push({kind:"text",types:new Set(Object.keys(o)),getText:y=>Promise.resolve(o[y])});r=!0}catch{}if(!r){let n=new Map;for(let a of e.items)if(a.kind==="string")n.set(a.type||ge,e.getData(a.type));else if(a.kind==="file")if(typeof a.webkitGetAsEntry=="function"){let o=a.webkitGetAsEntry();if(!o)continue;o.isFile?t.push(Fe(a.getAsFile())):o.isDirectory&&t.push($t(o))}else t.push(Fe(a.getAsFile()));n.size>0&&t.push({kind:"text",types:new Set(n.keys()),getText:a=>Promise.resolve(n.get(a))})}return t}function Mr(e){return typeof e.text=="function"?e.text():new Promise((t,r)=>{let n=new FileReader;n.onload=()=>{t(n.result)},n.onerror=r,n.readAsText(e)})}function Fe(e){if(!e)throw new Error("No file provided");return{kind:"file",type:e.type||ge,name:e.name,getText:()=>Mr(e),getFile:()=>Promise.resolve(e)}}function $t(e){return{kind:"directory",name:e.name,getEntries:()=>jr(e)}}async function*jr(e){let t=e.createReader(),r;do{r=await new Promise((n,a)=>{t.readEntries(n,a)});for(let n of r)if(n.isFile){let a=await Nr(n);yield Fe(a)}else n.isDirectory&&(yield $t(n))}while(r.length>0)}function Nr(e){return new Promise((t,r)=>e.file(t,r))}function Rr(e){return e.kind==="text"}let B={draggingKeys:new Set};function Lr(e){B.draggingCollectionRef=e}function Vr(e){B.draggingKeys=e}function Y(e){B.dropCollectionRef=e}function vt(){B={draggingKeys:new Set}}function Gr(e){B=e}function V(e){let{draggingCollectionRef:t,dropCollectionRef:r}=B;return t?.current!=null&&t.current===(e?.current||r?.current)}let ce;function ye(e){ce=e}let Se=P.none;function be(e){Se=e}let Pe=new Map,te=new Map,R=null,me=new Set;function Et(e){return Pe.set(e.element,e),R?.updateValidDropTargets(),()=>{Pe.delete(e.element),R?.updateValidDropTargets()}}function Hr(e){return te.set(e.element,e),()=>{te.delete(e.element)}}function zr(e,t){if(R)throw new Error("Cannot begin dragging while already dragging");R=new _r(e,t),requestAnimationFrame(()=>{R&&(R.setup(),Dt()==="keyboard"&&R.next())});for(let r of me)r()}function Me(){let[e,t]=x.useState(R);return x.useEffect(()=>{let r=()=>t(R);return me.add(r),()=>{me.delete(r)}},[]),e}function Ur(){return!!R}function Xr(){R=null;for(let e of me)e()}const Ye=["pointerdown","pointermove","pointerenter","pointerleave","pointerover","pointerout","pointerup","mousedown","mousemove","mouseenter","mouseleave","mouseover","mouseout","mouseup","touchstart","touchmove","touchend","focusin","focusout"],Yr=["pointerup","mouseup","touchend"],qr={keyboard:"dragStartedKeyboard",touch:"dragStartedTouch",virtual:"dragStartedVirtual"};class _r{constructor(t,r){this.validDropTargets=[],this.currentDropTarget=null,this.currentDropItem=null,this.dropOperation=null,this.mutationObserver=null,this.restoreAriaHidden=null,this.isVirtualClick=!1,this.dragTarget=t,this.stringFormatter=r,this.onKeyDown=this.onKeyDown.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onFocus=this.onFocus.bind(this),this.onBlur=this.onBlur.bind(this),this.onClick=this.onClick.bind(this),this.onPointerDown=this.onPointerDown.bind(this),this.cancelEvent=this.cancelEvent.bind(this),this.initialFocused=!1}setup(){document.addEventListener("keydown",this.onKeyDown,!0),document.addEventListener("keyup",this.onKeyUp,!0),window.addEventListener("focus",this.onFocus,!0),window.addEventListener("blur",this.onBlur,!0),document.addEventListener("click",this.onClick,!0),document.addEventListener("pointerdown",this.onPointerDown,!0);for(let t of Ye)document.addEventListener(t,this.cancelEvent,!0);this.mutationObserver=new MutationObserver(()=>this.updateValidDropTargets()),this.updateValidDropTargets(),ae(this.stringFormatter.format(qr[Dt()]))}teardown(){document.removeEventListener("keydown",this.onKeyDown,!0),document.removeEventListener("keyup",this.onKeyUp,!0),window.removeEventListener("focus",this.onFocus,!0),window.removeEventListener("blur",this.onBlur,!0),document.removeEventListener("click",this.onClick,!0),document.removeEventListener("pointerdown",this.onPointerDown,!0);for(let t of Ye)document.removeEventListener(t,this.cancelEvent,!0);this.mutationObserver?.disconnect(),this.restoreAriaHidden?.()}onKeyDown(t){if(this.cancelEvent(t),t.key==="Escape"){this.cancel();return}t.key==="Tab"&&!(t.metaKey||t.altKey||t.ctrlKey)&&(t.shiftKey?this.previous():this.next()),typeof this.currentDropTarget?.onKeyDown=="function"&&this.currentDropTarget.onKeyDown(t,this.dragTarget)}onKeyUp(t){this.cancelEvent(t),t.key==="Enter"&&(t.altKey||G(this.getCurrentActivateButton(),M(t))?this.activate(this.currentDropTarget,this.currentDropItem):this.drop())}getCurrentActivateButton(){return this.currentDropItem?.activateButtonRef?.current??this.currentDropTarget?.activateButtonRef?.current??null}onFocus(t){let r=this.getCurrentActivateButton(),n=M(t);if(n===r){this.cancelEvent(t);return}if(n!==this.dragTarget.element&&this.cancelEvent(t),!(n instanceof HTMLElement)||n===this.dragTarget.element)return;let a=this.validDropTargets.find(y=>y.element===n)||this.validDropTargets.find(y=>G(y.element,n));if(!a){this.currentDropTarget?this.currentDropTarget.element.focus():this.dragTarget.element.focus();return}let o=te.get(n);a&&this.setCurrentDropTarget(a,o)}onBlur(t){let r=this.getCurrentActivateButton();if(r&&t.relatedTarget===r){this.cancelEvent(t);return}M(t)!==this.dragTarget.element&&this.cancelEvent(t),(!t.relatedTarget||!(t.relatedTarget instanceof HTMLElement))&&(this.currentDropTarget?this.currentDropTarget.element.focus():this.dragTarget.element.focus())}onClick(t){if(this.cancelEvent(t),Qe(t)||this.isVirtualClick){let r=te.values(),n=M(t),a=[...r].find(c=>c.element===n||G(c.activateButtonRef?.current,n)),o=this.validDropTargets.find(c=>G(c.element,n)),y=a?.activateButtonRef?.current??o?.activateButtonRef?.current;if(G(y,n)&&o){this.activate(o,a);return}if(M(t)===this.dragTarget.element){this.cancel();return}o&&(this.setCurrentDropTarget(o,a),this.drop(a))}}onPointerDown(t){this.cancelEvent(t),this.isVirtualClick=et(t)}cancelEvent(t){let r=M(t);(t.type==="focusin"||t.type==="focusout")&&(r===this.dragTarget?.element||r===this.getCurrentActivateButton())||(Yr.includes(t.type)||t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation())}updateValidDropTargets(){if(!this.mutationObserver)return;if(this.mutationObserver.disconnect(),this.restoreAriaHidden&&this.restoreAriaHidden(),this.validDropTargets=Wr(this.dragTarget),this.validDropTargets.length>0){let a=this.findNearestDropTarget();this.validDropTargets=[...this.validDropTargets.slice(a),...this.validDropTargets.slice(0,a)]}this.currentDropTarget&&!this.validDropTargets.includes(this.currentDropTarget)&&this.setCurrentDropTarget(this.validDropTargets[0]);let t=z(this.dragTarget.items),r=[...te.values()].filter(a=>typeof a.getDropOperation=="function"?a.getDropOperation(t,this.dragTarget.allowedDropOperations)!=="cancel":!0),n=this.validDropTargets.filter(a=>!r.some(o=>G(a.element,o.element)));this.restoreAriaHidden=It([this.dragTarget.element,...r.flatMap(a=>a.activateButtonRef?.current?[a.element,a.activateButtonRef?.current]:[a.element]),...n.flatMap(a=>a.activateButtonRef?.current?[a.element,a.activateButtonRef?.current]:[a.element])],{shouldUseInert:!0}),this.mutationObserver.observe(document.body,{subtree:!0,attributes:!0,attributeFilter:["aria-hidden","inert"]})}next(){if(!this.currentDropTarget){this.setCurrentDropTarget(this.validDropTargets[0]);return}let t=this.validDropTargets.indexOf(this.currentDropTarget);if(t<0){this.setCurrentDropTarget(this.validDropTargets[0]);return}t===this.validDropTargets.length-1?this.dragTarget.element.closest('[aria-hidden="true"], [inert]')?this.setCurrentDropTarget(this.validDropTargets[0]):(this.setCurrentDropTarget(null),this.dragTarget.element.focus()):this.setCurrentDropTarget(this.validDropTargets[t+1])}previous(){if(!this.currentDropTarget){this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]);return}let t=this.validDropTargets.indexOf(this.currentDropTarget);if(t<0){this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]);return}t===0?this.dragTarget.element.closest('[aria-hidden="true"], [inert]')?this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]):(this.setCurrentDropTarget(null),this.dragTarget.element.focus()):this.setCurrentDropTarget(this.validDropTargets[t-1])}findNearestDropTarget(){let t=this.dragTarget.element.getBoundingClientRect(),r=1/0,n=-1,a=-1;for(let o=0;o=0?a:n}setCurrentDropTarget(t,r){if(t!==this.currentDropTarget){if(this.currentDropTarget&&typeof this.currentDropTarget.onDropExit=="function"){let n=this.currentDropTarget.element.getBoundingClientRect();this.currentDropTarget.onDropExit({type:"dropexit",x:n.left+n.width/2,y:n.top+n.height/2})}if(this.currentDropTarget=t,t){if(typeof t.onDropEnter=="function"){let n=t.element.getBoundingClientRect();t.onDropEnter({type:"dropenter",x:n.left+n.width/2,y:n.top+n.height/2},this.dragTarget)}r||t?.element.focus()}}if(r!=null&&r!==this.currentDropItem&&(this.currentDropTarget&&typeof this.currentDropTarget.onDropTargetEnter=="function"&&this.currentDropTarget.onDropTargetEnter(r.target),r.element.focus(),this.currentDropItem=r,!this.initialFocused)){let n=r?.element.getAttribute("aria-label");n&&ae(n,"polite"),this.initialFocused=!0}}end(){if(this.teardown(),Xr(),typeof this.dragTarget.onDragEnd=="function"){let r=(this.currentDropTarget&&this.dropOperation!=="cancel"?this.currentDropTarget:this.dragTarget).element.getBoundingClientRect();this.dragTarget.onDragEnd({type:"dragend",x:r.x+r.width/2,y:r.y+r.height/2,dropOperation:this.dropOperation||"cancel"})}this.currentDropTarget&&!this.currentDropTarget.preventFocusOnDrop&&Re()?.dispatchEvent(new FocusEvent("focusin",{bubbles:!0})),this.setCurrentDropTarget(null)}cancel(){this.setCurrentDropTarget(null),this.end(),this.dragTarget.element.closest('[aria-hidden="true"], [inert]')||this.dragTarget.element.focus(),Re()?.dispatchEvent(new FocusEvent("focusin",{bubbles:!0})),ae(this.stringFormatter.format("dropCanceled"))}drop(t){if(!this.currentDropTarget){this.cancel();return}if(typeof t?.getDropOperation=="function"){let r=z(this.dragTarget.items);this.dropOperation=t.getDropOperation(r,this.dragTarget.allowedDropOperations)}else if(typeof this.currentDropTarget.getDropOperation=="function"){let r=z(this.dragTarget.items);this.dropOperation=this.currentDropTarget.getDropOperation(r,this.dragTarget.allowedDropOperations)}else this.dropOperation=this.dragTarget.allowedDropOperations[0];if(typeof this.currentDropTarget.onDrop=="function"){let r=this.dragTarget.items.map(a=>({kind:"text",types:new Set(Object.keys(a)),getText:o=>Promise.resolve(a[o])})),n=this.currentDropTarget.element.getBoundingClientRect();this.currentDropTarget.onDrop({type:"drop",x:n.left+n.width/2,y:n.top+n.height/2,items:r,dropOperation:this.dropOperation},t?.target??null)}this.end(),ae(this.stringFormatter.format("dropComplete"))}activate(t,r){if(t&&typeof t.onDropActivate=="function"){let n=r?.target??null,a=t.element.getBoundingClientRect();t.onDropActivate({type:"dropactivate",x:a.left+a.width/2,y:a.top+a.height/2},n)}}}function Wr(e){let t=z(e.items);return[...Pe.values()].filter(r=>r.element.closest('[aria-hidden="true"], [inert]')?!1:typeof r.getDropOperation=="function"?r.getDropOperation(t,e.allowedDropOperations)!=="cancel":!0)}var xt={};xt={dragItem:e=>`Drag ${e.itemText}`,dragSelectedItems:(e,t)=>`Drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}`,dragDescriptionKeyboard:"Press Enter to start dragging.",dragDescriptionKeyboardAlt:"Press Alt + Enter to start dragging.",dragDescriptionTouch:"Double tap to start dragging.",dragDescriptionVirtual:"Click to start dragging.",dragDescriptionLongPress:"Long press to start dragging.",dragSelectedKeyboard:(e,t)=>`Press Enter to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragSelectedKeyboardAlt:(e,t)=>`Press Alt + Enter to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragSelectedLongPress:(e,t)=>`Long press to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragStartedKeyboard:"Started dragging. Press Tab to navigate to a drop target, then press Enter to drop, or press Escape to cancel.",dragStartedTouch:"Started dragging. Navigate to a drop target, then double tap to drop.",dragStartedVirtual:"Started dragging. Navigate to a drop target, then click or press Enter to drop.",endDragKeyboard:"Dragging. Press Enter to cancel drag.",endDragTouch:"Dragging. Double tap to cancel drag.",endDragVirtual:"Dragging. Click to cancel drag.",dropDescriptionKeyboard:"Press Enter to drop. Press Escape to cancel drag.",dropDescriptionTouch:"Double tap to drop.",dropDescriptionVirtual:"Click to drop.",dropCanceled:"Drop canceled.",dropComplete:"Drop complete.",dropIndicator:"drop indicator",dropOnRoot:"Drop on",dropOnItem:e=>`Drop on ${e.itemText}`,insertBefore:e=>`Insert before ${e.itemText}`,insertBetween:e=>`Insert between ${e.beforeItemText} and ${e.afterItemText}`,insertAfter:e=>`Insert after ${e.itemText}`};var wt={};wt={dragDescriptionKeyboard:"按 Enter 开始拖动。",dragDescriptionKeyboardAlt:"按 Alt + Enter 开始拖动。",dragDescriptionLongPress:"长按以开始拖动。",dragDescriptionTouch:"双击开始拖动。",dragDescriptionVirtual:"单击开始拖动。",dragItem:e=>`拖动 ${e.itemText}`,dragSelectedItems:(e,t)=>`拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 选中项目`,other:()=>`${t.number(e.count)} 选中项目`})}`,dragSelectedKeyboard:(e,t)=>`按 Enter 以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragSelectedKeyboardAlt:(e,t)=>`按 Alt + Enter 以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragSelectedLongPress:(e,t)=>`长按以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragStartedKeyboard:"已开始拖动。按 Tab 导航到放置目标,然后按 Enter 放置或按 Escape 取消。",dragStartedTouch:"已开始拖动。导航到放置目标,然后双击放置。",dragStartedVirtual:"已开始拖动。导航到放置目标,然后单击或按 Enter 放置。",dropCanceled:"放置已取消。",dropComplete:"放置已完成。",dropDescriptionKeyboard:"按 Enter 放置。按 Escape 取消拖动。",dropDescriptionTouch:"双击放置。",dropDescriptionVirtual:"单击放置。",dropIndicator:"放置标记",dropOnItem:e=>`放置于 ${e.itemText}`,dropOnRoot:"放置于",endDragKeyboard:"正在拖动。按 Enter 取消拖动。",endDragTouch:"正在拖动。双击取消拖动。",endDragVirtual:"正在拖动。单击取消拖动。",insertAfter:e=>`插入到 ${e.itemText} 之后`,insertBefore:e=>`插入到 ${e.itemText} 之前`,insertBetween:e=>`插入到 ${e.beforeItemText} 和 ${e.afterItemText} 之间`};var Tt={};Tt={dragDescriptionKeyboard:"按 Enter 鍵以開始拖曳。",dragDescriptionKeyboardAlt:"按 Alt+Enter 鍵以開始拖曳。",dragDescriptionLongPress:"長按以開始拖曳。",dragDescriptionTouch:"輕點兩下以開始拖曳。",dragDescriptionVirtual:"按一下滑鼠以開始拖曳。",dragItem:e=>`拖曳「${e.itemText}」`,dragSelectedItems:(e,t)=>`拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}`,dragSelectedKeyboard:(e,t)=>`按 Enter 鍵以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragSelectedKeyboardAlt:(e,t)=>`按 Alt+Enter 鍵以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragSelectedLongPress:(e,t)=>`長按以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragStartedKeyboard:"已開始拖曳。按 Tab 鍵以瀏覽至放置目標,然後按 Enter 鍵以放置,或按 Escape 鍵以取消。",dragStartedTouch:"已開始拖曳。瀏覽至放置目標,然後輕點兩下以放置。",dragStartedVirtual:"已開始拖曳。瀏覽至放置目標,然後按一下滑鼠或按 Enter 鍵以放置。",dropCanceled:"放置已取消。",dropComplete:"放置已完成。",dropDescriptionKeyboard:"按 Enter 鍵以放置。按 Escape 鍵以取消拖曳。",dropDescriptionTouch:"輕點兩下以放置。",dropDescriptionVirtual:"按一下滑鼠以放置。",dropIndicator:"放置指示器",dropOnItem:e=>`放置在「${e.itemText}」上`,dropOnRoot:"放置在",endDragKeyboard:"拖曳中。按 Enter 鍵以取消拖曳。",endDragTouch:"拖曳中。輕點兩下以取消拖曳。",endDragVirtual:"拖曳中。按一下滑鼠以取消拖曳。",insertAfter:e=>`插入至「${e.itemText}」之後`,insertBefore:e=>`插入至「${e.itemText}」之前`,insertBetween:e=>`插入至「${e.beforeItemText}」和「${e.afterItemText}」之間`};var ne={};ne={"ar-AE":F,"bg-BG":F,"cs-CZ":F,"da-DK":F,"de-DE":F,"el-GR":F,"en-US":xt,"es-ES":F,"et-EE":F,"fi-FI":F,"fr-FR":F,"he-IL":F,"hr-HR":F,"hu-HU":F,"it-IT":F,"ja-JP":F,"ko-KR":F,"lt-LT":F,"lv-LV":F,"nb-NO":F,"nl-NL":F,"pl-PL":F,"pt-BR":F,"pt-PT":F,"ro-RO":F,"ru-RU":F,"sk-SK":F,"sl-SI":F,"sr-SP":F,"sv-SE":F,"tr-TR":F,"uk-UA":F,"zh-CN":wt,"zh-TW":Tt};function Jr(e){return e&&e.__esModule?e.default:e}const Zr={keyboard:"dropDescriptionKeyboard",touch:"dropDescriptionTouch",virtual:"dropDescriptionVirtual"};function kt(){let e=re(Jr(ne),"@react-aria/dnd"),t=Oe(),r=Me();return{dropProps:{...Be(r?e.format(Zr[t]):""),onClick:()=>{}}}}const Qr=800;function Kt(e){let{hasDropButton:t,isDisabled:r}=e,[n,a]=x.useState(!1),o=x.useRef({x:0,y:0,dragOverElements:new Set,dropEffect:"none",allowedOperations:P.all,dropActivateTimer:void 0}).current,y=i=>{if(a(!0),typeof e.onDropEnter=="function"){let s=i.currentTarget.getBoundingClientRect();e.onDropEnter({type:"dropenter",x:i.clientX-s.x,y:i.clientY-s.y})}},c=i=>{if(a(!1),typeof e.onDropExit=="function"){let s=i.currentTarget.getBoundingClientRect();e.onDropExit({type:"dropexit",x:i.clientX-s.x,y:i.clientY-s.y})}},D=i=>{i.preventDefault(),i.stopPropagation();let s=qe(i);if(i.clientX===o.x&&i.clientY===o.y&&s===o.allowedOperations){i.dataTransfer.dropEffect=o.dropEffect;return}o.x=i.clientX,o.y=i.clientY;let u=o.dropEffect;if(s!==o.allowedOperations){let h=$e(s),w=h[0];if(typeof e.getDropOperation=="function"){let k=new ie(i.dataTransfer);w=le(s,e.getDropOperation(k,h))}o.dropEffect=De[w]||"none"}if(typeof e.getDropOperationForPoint=="function"){let h=new ie(i.dataTransfer),w=i.currentTarget.getBoundingClientRect(),k=le(s,e.getDropOperationForPoint(h,$e(s),o.x-w.x,o.y-w.y));o.dropEffect=De[k]||"none"}if(o.allowedOperations=s,i.dataTransfer.dropEffect=o.dropEffect,o.dropEffect==="none"&&u!=="none"?c(i):o.dropEffect!=="none"&&u==="none"&&y(i),typeof e.onDropMove=="function"&&o.dropEffect!=="none"){let h=i.currentTarget.getBoundingClientRect();e.onDropMove({type:"dropmove",x:o.x-h.x,y:o.y-h.y})}if(clearTimeout(o.dropActivateTimer),e.onDropActivate&&typeof e.onDropActivate=="function"&&o.dropEffect!=="none"){let h=e.onDropActivate,w=i.currentTarget.getBoundingClientRect();o.dropActivateTimer=setTimeout(()=>{h({type:"dropactivate",x:o.x-w.x,y:o.y-w.y})},Qr)}},v=i=>{if(i.preventDefault(),i.stopPropagation(),o.dragOverElements.add(M(i)),o.dragOverElements.size>1)return;let s=qe(i),u=$e(s),h=u[0];if(typeof e.getDropOperation=="function"){let w=new ie(i.dataTransfer);h=le(s,e.getDropOperation(w,u))}if(typeof e.getDropOperationForPoint=="function"){let w=new ie(i.dataTransfer),k=i.currentTarget.getBoundingClientRect();h=le(s,e.getDropOperationForPoint(w,u,i.clientX-k.x,i.clientY-k.y))}o.x=i.clientX,o.y=i.clientY,o.allowedOperations=s,o.dropEffect=De[h]||"none",i.dataTransfer.dropEffect=o.dropEffect,h!=="cancel"&&y(i)},g=i=>{i.preventDefault(),i.stopPropagation();let s=M(i);if(o.dragOverElements.delete(s),s===i.currentTarget)for(let u of o.dragOverElements)G(i.currentTarget,u)||o.dragOverElements.delete(u);o.dragOverElements.size>0||(o.dropEffect!=="none"&&c(i),clearTimeout(o.dropActivateTimer))},$=i=>{if(i.preventDefault(),i.stopPropagation(),ye(o.dropEffect),typeof e.onDrop=="function"){let u=ee[o.dropEffect],h=bt(i.dataTransfer),w=i.currentTarget.getBoundingClientRect(),k={type:"drop",x:i.clientX-w.x,y:i.clientY-w.y,items:h,dropOperation:u};e.onDrop(k)}let s={...B};o.dragOverElements.clear(),c(i),clearTimeout(o.dropActivateTimer),s.draggingCollectionRef==null?ye(void 0):Gr(s)},l=N(i=>{typeof e.onDropEnter=="function"&&e.onDropEnter(i)}),d=N(i=>{typeof e.onDropExit=="function"&&e.onDropExit(i)}),p=N(i=>{typeof e.onDropActivate=="function"&&e.onDropActivate(i)}),b=N(i=>{typeof e.onDrop=="function"&&e.onDrop(i)}),m=N((i,s)=>e.getDropOperation?e.getDropOperation(i,s):s[0]),{ref:E}=e;tt(()=>{if(!(r||!E.current))return Et({element:E.current,getDropOperation:m,onDropEnter(i){a(!0),l(i)},onDropExit(i){a(!1),d(i)},onDrop:b,onDropActivate:p})},[r,E]);let{dropProps:T}=kt();return r?{dropProps:{},dropButtonProps:{isDisabled:!0},isDropTarget:!1}:{dropProps:{...!t&&T,onDragEnter:v,onDragOver:D,onDragLeave:g,onDrop:$},dropButtonProps:{...t&&T},isDropTarget:n}}function qe(e){let t=ft[e.dataTransfer.effectAllowed];Se&&(t&=Se);let r=P.none;return At()?(e.altKey&&(r|=P.copy),e.ctrlKey&&!Ot()&&(r|=P.link),e.metaKey&&(r|=P.move)):(e.altKey&&(r|=P.link),e.shiftKey&&(r|=P.move),e.ctrlKey&&(r|=P.copy)),r?t&r:t}function $e(e){let t=[];return e&P.move&&t.push("move"),e&P.copy&&t.push("copy"),e&P.link&&t.push("link"),t}function le(e,t){let r=P[t];return e&r?t:"cancel"}const ve=new Map;function q(e,t){let r=ve.get(e);if(!r){let n=new Set,a=o=>{for(let y of n)y(o)};r={listener:a,handlers:n},ve.set(e,r),document.addEventListener(e,a)}return r.handlers.add(t),()=>{r.handlers.delete(t),r.handlers.size===0&&(document.removeEventListener(e,r.listener),ve.delete(e))}}function en(e){let{isDisabled:t}=e,r=x.useRef(!1),{focusProps:n}=Mt({onFocusChange:g=>{r.current=g}}),a=N(g=>{r.current&&e.getItems&&g.preventDefault()}),o=N(g=>{!r.current||!e.getItems||(g.preventDefault(),g.clipboardData&&(Ce(g.clipboardData,e.getItems({action:"copy"})),e.onCopy?.()))}),y=N(g=>{r.current&&e.onCut&&e.getItems&&g.preventDefault()}),c=N(g=>{!r.current||!e.onCut||!e.getItems||(g.preventDefault(),g.clipboardData&&(Ce(g.clipboardData,e.getItems({action:"cut"})),e.onCut()))}),D=N(g=>{r.current&&e.onPaste&&g.preventDefault()}),v=N(g=>{if(!(!r.current||!e.onPaste)&&(g.preventDefault(),g.clipboardData)){let $=bt(g.clipboardData);e.onPaste($)}});return x.useEffect(()=>{if(!t)return jt(q("beforecopy",a),q("copy",o),q("beforecut",y),q("cut",c),q("beforepaste",D),q("paste",v))},[t]),{clipboardProps:n}}function tn(e){return e&&e.__esModule?e.default:e}const rn=x.createContext(null),nn=x.forwardRef(function(t,r){let{isDisabled:n=!1}=t;[t,r]=Nt(t,r,rn);let a=Rt(r),o=x.useRef(null),{dropProps:y,dropButtonProps:c,isDropTarget:D}=Kt({...t,ref:o,hasDropButton:!0}),{buttonProps:v}=Lt(c||{},o),{hoverProps:g,isHovered:$}=Vt(t),{focusProps:l,isFocused:d,isFocusVisible:p}=Gt(),b=re(tn(Qt),"react-aria-components"),m=Ht(),E=t["aria-label"]||b.format("dropzoneLabel"),T=t["aria-labelledby"],i=[m,T].filter(Boolean).join(" "),s=zt({"aria-label":E,"aria-labelledby":i}),{clipboardProps:u}=en({isDisabled:n,onPaste:k=>t.onDrop?.({type:"drop",items:k,x:0,y:0,dropOperation:"copy"})}),h=Ut({...t,values:{isHovered:$,isFocused:d,isFocusVisible:p,isDropTarget:D,isDisabled:n},defaultClassName:"react-aria-DropZone"}),w=Xt(t,{global:!0});return delete w.id,_.createElement(Yt,{values:[[qt,{id:m,slot:"label"}]]},_.createElement(_t.div,{...ke(w,h,y,g),slot:t.slot||void 0,ref:a,onClick:k=>{let C=M(k);for(;C&&G(a.current,C)&&!Wt(C);){if(C===a.current&&o.current){Jt(o.current);break}C=C.parentElement}},"data-hovered":$||void 0,"data-focused":d||void 0,"data-focus-visible":p||void 0,"data-drop-target":D||void 0,"data-disabled":n||void 0},_.createElement(Zt,null,_.createElement("button",{...ke(v,l,u,s),ref:o})),h.children))});function an(e,t,r,n,a=!1,o=!1){switch(n){case"left":return a?Ee(e,t,r,o,"left"):xe(e,t,r,o,"left");case"right":return a?xe(e,t,r,o,"right"):Ee(e,t,r,o,"right");case"up":return xe(e,t,r,o);case"down":return Ee(e,t,r,o)}}function Ee(e,t,r,n=!1,a=null){if(!r)return{type:"root"};if(r.type==="root"){let o=e.getFirstKey?.()??null;return o!=null?{type:"item",key:o,dropPosition:"before"}:null}if(r.type==="item"){let o=null;a?o=a==="right"?e.getKeyRightOf?.(r.key,{includeDisabled:!0}):e.getKeyLeftOf?.(r.key,{includeDisabled:!0}):o=e.getKeyBelow?.(r.key,{includeDisabled:!0});let y=je(t,r.key,c=>t.getKeyAfter(c));if(o!=null&&o!==y)return{type:"item",key:o,dropPosition:r.dropPosition};switch(r.dropPosition){case"before":return{type:"item",key:r.key,dropPosition:"on"};case"on":{let c=t.getItem(r.key),D=o!=null?t.getItem(o):null;return c&&D&&D.level>=c.level?{type:"item",key:D.key,dropPosition:"before"}:{type:"item",key:r.key,dropPosition:"after"}}case"after":{let c=t.getItem(r.key),D=c?.nextKey!=null?t.getItem(c.nextKey):null;for(;D!=null&&D.type!=="item";)D=D.nextKey!=null?t.getItem(D.nextKey):null;if(c&&D==null&&c.parentKey!=null){let v=t.getItem(c.parentKey);const g=v?.nextKey!=null?t.getItem(v.nextKey):null;if(g?.type==="item")return{type:"item",key:g.key,dropPosition:"before"};if(v?.type==="item")return{type:"item",key:v.key,dropPosition:"after"}}if(D)return{type:"item",key:D.key,dropPosition:"on"}}}}return n?{type:"root"}:null}function xe(e,t,r,n=!1,a=null){if(!r||n&&r.type==="root"){let o=null,y=e.getLastKey?.();for(;y!=null;){let c=t.getItem(y);if(c?.type!=="item")break;o=y,y=c?.parentKey}return o!=null?{type:"item",key:o,dropPosition:"after"}:null}if(r.type==="item"){let o=null;a?o=a==="left"?e.getKeyLeftOf?.(r.key,{includeDisabled:!0}):e.getKeyRightOf?.(r.key,{includeDisabled:!0}):o=e.getKeyAbove?.(r.key,{includeDisabled:!0});let y=je(t,r.key,c=>t.getKeyBefore(c));if(o!=null&&o!==y)return{type:"item",key:o,dropPosition:r.dropPosition};switch(r.dropPosition){case"before":{let c=t.getItem(r.key);if(c&&c.prevKey!=null){let D=_e(t,c.prevKey);if(D)return D}return o!=null?{type:"item",key:o,dropPosition:"on"}:{type:"root"}}case"on":return{type:"item",key:r.key,dropPosition:"before"};case"after":{let c=_e(t,r.key);return c||{type:"item",key:r.key,dropPosition:"on"}}}}return r.type!=="root"?{type:"root"}:null}function _e(e,t){let r=e.getItem(t),n=je(e,t,o=>e.getKeyAfter(o)),a=n!=null?e.getItem(n):null;if(r&&a&&a.level>r.level){let o=null;if("lastChildKey"in r)for(o=r.lastChildKey!=null?e.getItem(r.lastChildKey):null;o&&o.type!=="item"&&o.prevKey!=null;)o=e.getItem(o.prevKey);else o=Array.from(r.childNodes).findLast(y=>y.type==="item")||null;if(o)return{type:"item",key:o.key,dropPosition:"after"}}return null}function je(e,t,r){let n=r(t),a=n!=null?e.getItem(n):null;for(;a&&a.type!=="item";)n=r(a.key),a=n!=null?e.getItem(n):null;return n}const se=20;function on(e){let t=x.useRef(null),r=x.useRef(!0),n=x.useRef(!0);x.useEffect(()=>{if(e.current){t.current=er(e.current)?e.current:tr(e.current);let y=window.getComputedStyle(t.current);r.current=/(auto|scroll)/.test(y.overflowX),n.current=/(auto|scroll)/.test(y.overflowY)}},[e]);let a=x.useRef({timer:void 0,dx:0,dy:0}).current;x.useEffect(()=>()=>{a.timer&&(cancelAnimationFrame(a.timer),a.timer=void 0)},[a]);let o=x.useCallback(()=>{r.current&&t.current&&(t.current.scrollLeft+=a.dx),n.current&&t.current&&(t.current.scrollTop+=a.dy),a.timer&&(a.timer=requestAnimationFrame(o))},[t,a]);return{move(y,c){if(!rt()||nt()||!t.current)return;let D=t.current.getBoundingClientRect(),v=se,g=se,$=D.height-se,l=D.width-se;yl||c$?(yl&&(a.dx=y-l),c$&&(a.dy=c-$),a.timer||(a.timer=requestAnimationFrame(o))):this.stop()},stop(){a.timer&&(cancelAnimationFrame(a.timer),a.timer=void 0)}}}function ln(e,t,r){let n=x.useRef({props:e,state:t,nextTarget:null,dropOperation:null}).current;n.props=e,n.state=t;let a=x.useCallback(async l=>{let{onInsert:d,onRootDrop:p,onItemDrop:b,onReorder:m,onMove:E,acceptedDragTypes:T="all",shouldAcceptItemDrop:i}=n.props,{draggingKeys:s}=B,u=V(r),{target:h,dropOperation:w,items:k}=l,C=k;(T!=="all"||i)&&(C=k.filter(S=>{let I;return S.kind==="directory"?I=new Set([mt]):I=S.kind==="file"?new Set([S.type]):S.types,T==="all"||T.some(H=>I.has(H))?h.type==="item"&&h.dropPosition==="on"&&i?i(h,I):!0:!1})),C.length>0&&(h.type==="root"&&p&&await p({items:C,dropOperation:w}),h.type==="item"&&(h.dropPosition==="on"&&b&&await b({items:C,dropOperation:w,isInternal:u,target:h}),E&&u&&await E({keys:s,dropOperation:w,target:h}),h.dropPosition!=="on"&&(!u&&d&&await d({items:C,dropOperation:w,target:h}),u&&m&&await m({keys:s,dropOperation:w,target:h}))))},[n,r]),o=on(r),{dropProps:y}=Kt({ref:r,onDropEnter(){n.nextTarget!=null&&t.setTarget(n.nextTarget)},onDropMove(l){n.nextTarget!=null&&t.setTarget(n.nextTarget),o.move(l.x,l.y)},getDropOperationForPoint(l,d,p,b){let{draggingKeys:m,dropCollectionRef:E}=B,T=V(r),i=u=>t.getDropOperation({target:u,types:l,allowedOperations:d,isInternal:T,draggingKeys:m})!=="cancel",s=e.dropTargetDelegate.getDropTargetFromPoint(p,b,i);if(!s)return n.dropOperation="cancel",n.nextTarget=null,"cancel";if(n.dropOperation=t.getDropOperation({target:s,types:l,allowedOperations:d,isInternal:T,draggingKeys:m}),n.dropOperation==="cancel"){let u={type:"root"},h=t.getDropOperation({target:u,types:l,allowedOperations:d,isInternal:T,draggingKeys:m});h!=="cancel"&&(s=u,n.dropOperation=h)}return s&&n.dropOperation!=="cancel"&&r?.current!==E?.current&&Y(r),n.nextTarget=n.dropOperation==="cancel"?null:s,n.dropOperation},onDropExit(){Y(void 0),t.setTarget(null),o.stop()},onDropActivate(l){t.target?.type==="item"&&typeof e.onDropActivate=="function"&&e.onDropActivate({type:"dropactivate",x:l.x,y:l.y,target:t.target})},onDrop(l){Y(r),t.target&&v(l,t.target);let{draggingCollectionRef:d}=B;d==null&&vt()}}),c=x.useRef(null),D=x.useCallback(()=>{let{state:l}=n;if(c.current){let{target:d,collection:p,selectedKeys:b,focusedKey:m,isInternal:E,draggingKeys:T}=c.current;if(l.collection.size>p.size&&l.selectionManager.isSelectionEqual(b)){let i=new Set,s=l.collection.getFirstKey();for(;s!=null;){let u=l.collection.getItem(s);u?.type==="item"&&!p.getItem(u.key)&&i.add(u.key),u?.hasChildNodes&&l.collection.getItem(u.lastChildKey)?.type==="item"?s=u.firstChildKey:s=l.collection.getKeyAfter(s)}if(l.selectionManager.setSelectedKeys(i),l.selectionManager.focusedKey===m){let u=i.keys().next().value;if(u!=null){let h=l.collection.getItem(u),w=c.current.target,k=l.collection.expandedKeys?l.collection.expandedKeys.has(h?.parentKey):!1;h&&(h?.type==="cell"||w.type==="item"&&w.dropPosition==="on"&&!k)&&(u=h.parentKey),u!=null&&l.selectionManager.setFocusedKey(u),l.selectionManager.selectionMode==="none"&&oe("keyboard")}}}else m!=null&&l.selectionManager.focusedKey===m&&E&&d.type==="item"&&d.dropPosition!=="on"&&T.has(l.collection.getItem(m)?.parentKey)?(l.selectionManager.setFocusedKey(l.collection.getItem(m)?.parentKey??null),oe("keyboard")):l.selectionManager.focusedKey===m&&d.type==="item"&&d.dropPosition==="on"&&l.collection.getItem(d.key)!=null?(l.selectionManager.setFocusedKey(d.key),oe("keyboard")):l.selectionManager.focusedKey!=null&&!l.selectionManager.isSelected(l.selectionManager.focusedKey)&&oe("keyboard");l.selectionManager.setFocused(!0)}},[n]),v=x.useCallback((l,d)=>{let{state:p}=n;c.current={timeout:void 0,focusedKey:p.selectionManager.focusedKey,collection:p.collection,selectedKeys:p.selectionManager.selectedKeys,draggingKeys:B.draggingKeys,isInternal:V(r),target:d},(n.props.onDrop||a)({type:"drop",x:l.x,y:l.y,target:d,items:l.items,dropOperation:l.dropOperation}),c.current.timeout=setTimeout(()=>{D(),c.current=null},50)},[n,a,r,D]);x.useEffect(()=>()=>{c.current&&clearTimeout(c.current.timeout)},[]),tt(()=>{c.current&&t.collection!==c.current.collection&&D()});let{direction:g}=rr();x.useEffect(()=>{if(!r.current)return;let l=(b,m=!0,E="down")=>an(n.props.keyboardDelegate,n.state.collection,b,E,g==="rtl",m),d=(b,m=!0)=>l(b,m,"up"),p=(b,m,E,T,i=!0)=>{let s=0,u,{draggingKeys:h}=B,w=V(r);do{let k=T(b,i);if(!k)return null;b=k,u=n.state.getDropOperation({target:k,types:m,allowedOperations:E,isInternal:w,draggingKeys:h}),b.type==="root"&&s++}while(u==="cancel"&&!n.state.isDropTarget(b)&&s<2);return u==="cancel"?null:b};return Et({element:r.current,preventFocusOnDrop:!0,getDropOperation(b,m){if(n.state.target){let{draggingKeys:T}=B,i=V(r);return n.state.getDropOperation({target:n.state.target,types:b,allowedOperations:m,isInternal:i,draggingKeys:T})}return p(null,b,m,l)?"move":"cancel"},onDropEnter(b,m){let E=z(m.items),T=n.state.selectionManager,i=null;Y(r);let s=T.focusedKey,u="after",h=s!=null?n.state.collection.getItem(s):null;if(h?.type==="cell"&&(s=h.parentKey),s!=null&&T.isSelected(s)&&(T.selectedKeys.size>1&&T.firstSelectedKey===s?u="before":s=T.lastSelectedKey),s!=null){i={type:"item",key:s,dropPosition:u};let{draggingKeys:w}=B,k=V(r);n.state.getDropOperation({target:i,types:E,allowedOperations:m.allowedDropOperations,isInternal:k,draggingKeys:w})==="cancel"&&(i=p(i,E,m.allowedDropOperations,l,!1)??p(i,E,m.allowedDropOperations,d,!1))}i||(i=p(null,E,m.allowedDropOperations,l)),n.state.setTarget(i)},onDropExit(){Y(void 0),n.state.setTarget(null)},onDropTargetEnter(b){n.state.setTarget(b)},onDropActivate(b,m){m?.type==="item"&&m?.dropPosition==="on"&&typeof n.props.onDropActivate=="function"&&n.props.onDropActivate({type:"dropactivate",x:b.x,y:b.y,target:m})},onDrop(b,m){Y(r),n.state.target&&v(b,m||n.state.target)},onKeyDown(b,m){let{keyboardDelegate:E}=n.props,T=z(m.items);switch(b.key){case"ArrowDown":if(E.getKeyBelow){let i=p(n.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"down"));n.state.setTarget(i)}break;case"ArrowUp":if(E.getKeyAbove){let i=p(n.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"up"));n.state.setTarget(i)}break;case"ArrowLeft":if(E.getKeyLeftOf){let i=p(n.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"left"));n.state.setTarget(i)}break;case"ArrowRight":if(E.getKeyRightOf){let i=p(n.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"right"));n.state.setTarget(i)}break;case"Home":if(E.getFirstKey){let i=p(null,T,m.allowedDropOperations,l);n.state.setTarget(i)}break;case"End":if(E.getLastKey){let i=p(null,T,m.allowedDropOperations,d);n.state.setTarget(i)}break;case"PageDown":if(E.getKeyPageBelow){let i=n.state.target;if(!i)i=p(null,T,m.allowedDropOperations,l);else{let s=E.getFirstKey?.();i.type==="item"&&(s=i.key);let u=null;s!=null&&(u=E.getKeyPageBelow(s));let h=i.type==="item"?i.dropPosition:"after";if((u==null||i.type==="item"&&i.key===E.getLastKey?.())&&(u=E.getLastKey?.()??null,h="after"),u==null)break;i={type:"item",key:u,dropPosition:h};let{draggingCollectionRef:w,draggingKeys:k}=B,C=w?.current===r?.current;n.state.getDropOperation({target:i,types:T,allowedOperations:m.allowedDropOperations,isInternal:C,draggingKeys:k})==="cancel"&&(i=p(i,T,m.allowedDropOperations,l,!1)??p(i,T,m.allowedDropOperations,d,!1))}n.state.setTarget(i??n.state.target)}break;case"PageUp":{if(!E.getKeyPageAbove)break;let i=n.state.target;if(!i)i=p(null,T,m.allowedDropOperations,d);else if(i.type==="item"){if(i.key===E.getFirstKey?.())i={type:"root"};else{let w=E.getKeyPageAbove(i.key),k=i.dropPosition;if(w==null&&(w=E.getFirstKey?.(),k="before"),w==null)break;i={type:"item",key:w,dropPosition:k}}let{draggingKeys:s}=B,u=V(r);n.state.getDropOperation({target:i,types:T,allowedOperations:m.allowedDropOperations,isInternal:u,draggingKeys:s})==="cancel"&&(i=p(i,T,m.allowedDropOperations,d,!1)??p(i,T,m.allowedDropOperations,l,!1))}n.state.setTarget(i??n.state.target);break}}n.props.onKeyDown?.(b)}})},[n,r,v,g]);let $=at();return Ae.set(t,{id:$,ref:r}),{collectionProps:ke(y,{id:$,"aria-describedby":null})}}function Ct(e,t,r){let{dropProps:n}=kt(),a=Or(t);x.useEffect(()=>{if(r.current)return Hr({element:r.current,target:e.target,getDropOperation(g,$){let{draggingKeys:l}=B,d=V(a);return t.getDropOperation({target:e.target,types:g,allowedOperations:$,isInternal:d,draggingKeys:l})},activateButtonRef:e.activateButtonRef})},[r,e.target,t,a,e.activateButtonRef]);let o=Me(),{draggingKeys:y}=B,c=V(a),D=o&&t.getDropOperation({target:e.target,types:z(o.dragTarget.items),allowedOperations:o.dragTarget.allowedDropOperations,isInternal:c,draggingKeys:y})!=="cancel",v=t.isDropTarget(e.target);return x.useEffect(()=>{o&&v&&r.current&&r.current.focus()},[v,o,r]),{dropProps:{...n,"aria-hidden":!o||D?void 0:"true"},isDropTarget:v}}function sn(e){return e&&e.__esModule?e.default:e}function un(e,t,r){let{target:n}=e,{collection:a}=t,o=re(sn(ne),"@react-aria/dnd"),y=Me(),{dropProps:c}=Ct(e,t,r),D=at(),v=p=>p==null?"":a.getTextValue?.(p)??a.getItem(p)?.textValue??"",g="",$;if(n.type==="root")g=o.format("dropOnRoot"),$=`${D} ${Ar(t)}`;else if(n.dropPosition==="on")g=o.format("dropOnItem",{itemText:v(n.key)});else{let p,b;if(n.dropPosition==="before"){let m=a.getItem(n.key)?.prevKey,E=m!=null?a.getItem(m):null;p=E?.type==="item"?E.key:null}else p=n.key;if(n.dropPosition==="after"){let m=a.getItem(n.key)?.nextKey,E=m!=null?a.getItem(m):null;b=E?.type==="item"?E.key:null}else b=n.key;p!=null&&b!=null?g=o.format("insertBetween",{beforeItemText:v(p),afterItemText:v(b)}):p!=null?g=o.format("insertAfter",{itemText:v(p)}):b!=null&&(g=o.format("insertBefore",{itemText:v(b)}))}let l=t.isDropTarget(n),d=y?c["aria-hidden"]:"true";return{dropIndicatorProps:{...c,id:D,"aria-roledescription":o.format("dropIndicator"),"aria-label":g,"aria-labelledby":$,"aria-hidden":d,tabIndex:-1},isDropTarget:l,isHidden:!l&&!!d}}function dn(e){return e&&e.__esModule?e.default:e}const We={keyboard:{start:"dragDescriptionKeyboard",end:"endDragKeyboard"},touch:{start:"dragDescriptionTouch",end:"endDragTouch"},virtual:{start:"dragDescriptionVirtual",end:"endDragVirtual"}};function cn(e){let{hasDragButton:t,isDisabled:r}=e,n=re(dn(ne),"@react-aria/dnd"),a=x.useRef({options:e,x:0,y:0}).current;a.options=e;let o=x.useRef(null),[y,c]=x.useState(!1),D=u=>{o.current=u,c(!!u)},{addGlobalListener:v,removeAllGlobalListeners:g}=nr(),$=x.useRef(null),l=u=>{if(u.defaultPrevented)return;if(u.stopPropagation(),$.current==="virtual"){u.preventDefault(),m(M(u)),$.current=null;return}typeof e.onDragStart=="function"&&e.onDragStart({type:"dragstart",x:u.clientX,y:u.clientY});let h=e.getItems();u.dataTransfer.clearData?.(),Ce(u.dataTransfer,h);let w=P.all;if(typeof e.getAllowedDropOperations=="function"){let S=e.getAllowedDropOperations();w=P.none;for(let I of S)w|=P[I]||P.none}be(w);let k=gt[w]||"none";u.dataTransfer.effectAllowed=k==="cancel"?"none":k,typeof e.preview?.current=="function"&&e.preview.current(h,(S,I,H)=>{if(!S)return;let j=S.getBoundingClientRect(),U=u.currentTarget.getBoundingClientRect(),J=u.clientX-U.x,Z=u.clientY-U.y;(J>j.width||Z>j.height)&&(J=j.width/2,Z=j.height/2);let X=J,K=Z;typeof I=="number"&&typeof H=="number"&&(X=I,K=H),X=Math.max(0,Math.min(X,j.width)),K=Math.max(0,Math.min(K,j.height));let A=2*Math.round(j.height/2);S.style.height=`${A}px`,u.dataTransfer.setDragImage(S,X,K)}),v(window,"drop",S=>{S.preventDefault(),S.stopPropagation(),console.warn("Drags initiated from the React Aria useDrag hook may only be dropped on a target created with useDrop. This ensures that a keyboard and screen reader accessible alternative is available.")},{once:!0}),a.x=u.clientX,a.y=u.clientY;let C=M(u);requestAnimationFrame(()=>{D(C)})},d=u=>{u.stopPropagation(),!(u.clientX===a.x&&u.clientY===a.y)&&(typeof e.onDragMove=="function"&&e.onDragMove({type:"dragmove",x:u.clientX,y:u.clientY}),a.x=u.clientX,a.y=u.clientY)},p=u=>{if(u.stopPropagation(),typeof e.onDragEnd=="function"){let h={type:"dragend",x:u.clientX,y:u.clientY,dropOperation:ee[u.dataTransfer.dropEffect]};ce&&(h.dropOperation=ee[ce]),e.onDragEnd(h)}D(null),g(),be(P.none),ye(void 0)};x.useEffect(()=>()=>{if(o.current&&(!o.current.isConnected||parseInt(x.version,10)<17)){if(typeof a.options.onDragEnd=="function"){let u={type:"dragend",x:0,y:0,dropOperation:ee[ce||"none"]};a.options.onDragEnd(u)}D(null),be(P.none),ye(void 0)}},[a]);let b=u=>{u.pointerType!=="keyboard"&&u.pointerType!=="virtual"||m(u.target)},m=u=>{if(typeof a.options.onDragStart=="function"){let h=u.getBoundingClientRect();a.options.onDragStart({type:"dragstart",x:h.x+h.width/2,y:h.y+h.height/2})}zr({element:u,items:a.options.getItems(),allowedDropOperations:typeof a.options.getAllowedDropOperations=="function"?a.options.getAllowedDropOperations():["move","copy","link"],onDragEnd(h){D(null),typeof a.options.onDragEnd=="function"&&a.options.onDragEnd(h)}},n),D(u)},E=Oe(),T=y?We[E].end:We[E].start,i=Be(n.format(T)),s={};return t||(s={...i,onPointerDown(u){if($.current=et(u.nativeEvent)?"virtual":u.pointerType,u.width<1&&u.height<1&&nt()&&rt())$.current="virtual";else{let h=u.currentTarget.getBoundingClientRect(),w=u.clientX-h.x,k=u.clientY-h.y,C=h.width/2,S=h.height/2;Math.abs(w-C)<=.5&&Math.abs(k-S)<=.5?$.current="virtual":$.current=u.pointerType}},onKeyDownCapture(u){M(u)===u.currentTarget&&u.key==="Enter"&&(u.preventDefault(),u.stopPropagation())},onKeyUpCapture(u){M(u)===u.currentTarget&&u.key==="Enter"&&(u.preventDefault(),u.stopPropagation(),m(M(u)))},onClick(u){(Qe(u.nativeEvent)||$.current==="virtual")&&(u.preventDefault(),u.stopPropagation(),m(M(u)))}}),r?{dragProps:{draggable:"false"},dragButtonProps:{},isDragging:!1}:{dragProps:{...s,draggable:"true",onDragStart:l,onDrag:d,onDragEnd:p},dragButtonProps:{...i,onPress:b},isDragging:y}}function pn(e){return e&&e.__esModule?e.default:e}const fn={keyboard:{selected:"dragSelectedKeyboard",notSelected:"dragDescriptionKeyboard"},touch:{selected:"dragSelectedLongPress",notSelected:"dragDescriptionLongPress"},virtual:{selected:"dragDescriptionVirtual",notSelected:"dragDescriptionVirtual"}};function gn(e,t){let r=re(pn(ne),"@react-aria/dnd"),n=t.isDisabled||t.selectionManager.isDisabled(e.key),{dragProps:a,dragButtonProps:o}=cn({getItems(){return t.getItems(e.key)},preview:t.preview,getAllowedDropOperations:t.getAllowedDropOperations,hasDragButton:e.hasDragButton,onDragStart(d){t.startDrag(e.key,d),Vr(t.draggingKeys)},onDragMove(d){t.moveDrag(d)},onDragEnd(d){let{dropOperation:p}=d,b=p==="cancel"?!1:V();t.endDrag({...d,keys:t.draggingKeys,isInternal:b}),vt()}}),y=t.collection.getItem(e.key),c=t.getKeysForDrag(e.key).size,D=c>1&&t.selectionManager.isSelected(e.key),v,g,$=Oe();if(!e.hasDragButton&&t.selectionManager.selectionMode!=="none"){let d=fn[$][D?"selected":"notSelected"];e.hasAction&&$==="keyboard"&&(d+="Alt"),D?g=r.format(d,{count:c}):g=r.format(d),delete a.onClick}else if(D)v=r.format("dragSelectedItems",{count:c});else{let d=t.collection.getTextValue?.(e.key)??y?.textValue??"";v=r.format("dragItem",{itemText:d})}let l=Be(g);if(g&&Object.assign(a,l),!e.hasDragButton&&e.hasAction){let{onKeyDownCapture:d,onKeyUpCapture:p}=a;$==="touch"&&delete a["aria-describedby"],a.onKeyDownCapture=b=>{b.altKey&&d?.(b)},a.onKeyUpCapture=b=>{b.altKey&&p?.(b)}}return{dragProps:n?{}:a,dragButtonProps:{...o,isDisabled:n,"aria-label":v}}}function yn(e,t,r){let{draggingCollectionRef:n}=B;t.draggingKeys.size>0&&n?.current!==r.current&&Lr(r)}const mn=_.forwardRef(function(t,r){let n=t.children,[a,o]=x.useState(null),y=x.useRef(null),c=x.useRef(void 0);return x.useImperativeHandle(r,()=>(D,v)=>{let g=n(D),$,l,d;g&&typeof g=="object"&&"element"in g?($=g.element,l=g.x,d=g.y):$=g,St.flushSync(()=>{o($)}),v(y.current,l,d),c.current=requestAnimationFrame(()=>{o(null)})},[n]),x.useEffect(()=>()=>{c.current&&cancelAnimationFrame(c.current)},[]),a?_.createElement("div",{style:{zIndex:-100,position:"fixed",top:0,left:-1e5},ref:y},a):null});function hn(e){let{getItems:t,isDisabled:r,collection:n,selectionManager:a,onDragStart:o,onDragMove:y,onDragEnd:c,preview:D,getAllowedDropOperations:v}=e,[,g]=x.useState(!1),$=x.useRef(new Set),l=x.useRef(null),d=p=>{let b=new Set;if(a.isSelected(p))for(let m of a.selectedKeys){let E=n.getItem(m);if(E){let T=!1,i=E.parentKey;for(;i!=null;){if(a.selectedKeys.has(i)){T=!0;break}let s=n.getItem(i);i=s?s.parentKey:null}T||b.add(m)}}else b.add(p);return b};return{collection:n,selectionManager:a,get draggedKey(){return l.current},get draggingKeys(){return $.current},isDragging(p){return $.current.has(p)},getKeysForDrag:d,getItems(p){let b=d(p),m=[];for(let E of b){let T=n.getItem(E)?.value;T!=null&&m.push(T)}return t(d(p),m)},isDisabled:r,preview:D,getAllowedDropOperations:v,startDrag(p,b){let m=d(p);$.current=m,l.current=p,a.setFocused(!1),g(!0),typeof o=="function"&&o({...b,keys:m})},moveDrag(p){typeof y=="function"&&y({...p,keys:$.current})},endDrag(p){let{isInternal:b}=p;typeof c=="function"&&c({...p,keys:$.current,isInternal:b}),$.current=new Set,l.current=null,g(!1)}}}function Dn(e){let{acceptedDragTypes:t="all",isDisabled:r,onInsert:n,onRootDrop:a,onItemDrop:o,onReorder:y,onMove:c,shouldAcceptItemDrop:D,collection:v,selectionManager:g,onDropEnter:$,getDropOperation:l,onDrop:d}=e,[p,b]=x.useState(null),m=x.useRef(null),E=i=>{if(i.dropPosition==="before"){let s=v.getItem(i.key);return s&&s.prevKey!=null?{type:"item",key:s.prevKey,dropPosition:"after"}:null}else if(i.dropPosition==="after"){let s=v.getItem(i.key);return s&&s.nextKey!=null?{type:"item",key:s.nextKey,dropPosition:"before"}:null}return null},T=x.useCallback(i=>{let{target:s,types:u,allowedOperations:h,isInternal:w,draggingKeys:k}=i;if(r||!s)return"cancel";if(t==="all"||t.some(C=>u.has(C))){let C=n&&s.type==="item"&&!w&&(s.dropPosition==="before"||s.dropPosition==="after"),S=y&&s.type==="item"&&w&&(s.dropPosition==="before"||s.dropPosition==="after")&&bn(v,s,k),I=s.type!=="item"||s.dropPosition!=="on"||!D||D(s,u),H=c&&s.type==="item"&&w&&I,j=a&&s.type==="root"&&!w,U=o&&s.type==="item"&&s.dropPosition==="on"&&!(w&&s.key!=null&&k.has(s.key))&&I;if(d||C||S||H||j||U)return l?l(s,u,h):h[0]}return"cancel"},[r,v,t,l,n,a,o,D,y,c,d]);return{collection:v,selectionManager:g,isDisabled:r,target:p,setTarget(i){if(this.isDropTarget(i))return;let s=m.current;s&&typeof e.onDropExit=="function"&&e.onDropExit({type:"dropexit",x:0,y:0,target:s}),i&&typeof $=="function"&&$({type:"dropenter",x:0,y:0,target:i}),m.current=i??null,b(i??null)},isDropTarget(i){let s=m.current;return!s||!i?!1:we(i,s)?!0:i?.type==="item"&&s?.type==="item"&&i.key!==s.key&&i.dropPosition!==s.dropPosition&&i.dropPosition!=="on"&&s.dropPosition!=="on"?we(E(i),s)||we(i,E(s)):!1},getDropOperation(i){let{target:s,isInternal:u,draggingKeys:h}=i;if(u&&s.type==="item"&&h.size>0){if(h.has(s.key)&&s.dropPosition==="on")return"cancel";let w=s.key;for(;w!=null;){let C=v.getItem(w)?.parentKey;if(C!=null&&h.has(C))return"cancel";w=C??null}}return T(i)}}}function we(e,t){if(!e)return!t;switch(e.type){case"root":return t?.type==="root";case"item":return t?.type==="item"&&t?.key===e.key&&t?.dropPosition===e.dropPosition}}function bn(e,t,r){let n=e.getItem(t.key);for(let a of r)if(e.getItem(a)?.parentKey!==n?.parentKey)return!1;return!0}class $n{constructor(t,r,n){this.collection=t,this.ref=r,this.layout=n?.layout||"stack",this.orientation=n?.orientation||"vertical",this.direction=n?.direction||"ltr"}getPrimaryStart(t){return this.orientation==="horizontal"?t.left:t.top}getPrimaryEnd(t){return this.orientation==="horizontal"?t.right:t.bottom}getSecondaryStart(t){return this.orientation==="horizontal"?t.top:t.left}getSecondaryEnd(t){return this.orientation==="horizontal"?t.bottom:t.right}getFlowStart(t){return this.layout==="stack"?this.getPrimaryStart(t):this.getSecondaryStart(t)}getFlowEnd(t){return this.layout==="stack"?this.getPrimaryEnd(t):this.getSecondaryEnd(t)}getFlowSize(t){return this.getFlowEnd(t)-this.getFlowStart(t)}getDropTargetFromPoint(t,r,n){if(this.collection[Symbol.iterator]().next().done||!this.ref.current)return{type:"root"};let a=this.ref.current.getBoundingClientRect(),o=this.orientation==="horizontal"?t:r,y=this.orientation==="horizontal"?r:t;o+=this.getPrimaryStart(a),y+=this.getSecondaryStart(a);let c=this.layout==="stack"?o:y,D=this.orientation==="horizontal"&&this.direction==="rtl",v=this.layout==="grid"&&this.orientation==="vertical"&&this.direction==="rtl",g=this.layout==="stack"?D:v,$=this.ref.current?.dataset.collection,l=this.ref.current.querySelectorAll($?`[data-collection="${CSS.escape($)}"]`:"[data-key]"),d=new Map;for(let i of l)i instanceof HTMLElement&&i.dataset.key!=null&&d.set(i.dataset.key,i);let p=[...this.collection].filter(i=>i.type==="item");if(p.length<1)return{type:"root"};let b=0,m=p.length;for(;b{k?b=i+1:m=i};if(othis.getPrimaryEnd(h))w(!D);else if(ythis.getSecondaryEnd(h))w(!v);else{let k={type:"item",key:s.key,dropPosition:"on"};if(n(k))c<=this.getFlowStart(h)+5&&n({...k,dropPosition:"before"})?k.dropPosition=g?"after":"before":c>=this.getFlowEnd(h)-5&&n({...k,dropPosition:"after"})&&(k.dropPosition=g?"before":"after");else{let C=this.getFlowStart(h)+this.getFlowSize(h)/2;c<=C&&n({...k,dropPosition:"before"})?k.dropPosition=g?"after":"before":c>=C&&n({...k,dropPosition:"after"})&&(k.dropPosition=g?"before":"after")}return k}}let E=p[Math.min(b,p.length-1)];return a=d.get(String(E.key))?.getBoundingClientRect(),a&&(o{let{onDrop:r,onInsert:n,onItemDrop:a,onReorder:o,onMove:y,onRootDrop:c,getItems:D,renderDragPreview:v,renderDropIndicator:g,dropTargetDelegate:$}=e,l=!!D,d=!!(r||n||a||o||y||c),p={};return l&&(p.useDraggableCollectionState=function(m){return hn({...m,...e})},p.useDraggableCollection=yn,p.useDraggableItem=gn,p.DragPreview=mn,p.renderDragPreview=v,p.isVirtualDragging=Ur),d&&(p.useDroppableCollectionState=function(m){return Dn({...m,...e})},p.useDroppableItem=Ct,p.useDroppableCollection=function(m,E,T){return ln({...m,...e},E,T)},p.useDropIndicator=un,p.renderDropIndicator=g,p.dropTargetDelegate=$,p.ListDropTargetDelegate=$n),p},[e])}}function ue({children:e,tone:t,action:r}){return f.jsxs("span",{className:Ie("rp-tag",t),children:[f.jsx("span",{className:"rp-tag-label",children:e}),r]})}function Je({label:e,children:t}){return f.jsx("div",{className:"rp-tags",role:"group","aria-label":e,children:t})}function En({label:e,message:t,children:r}){return f.jsxs("div",{className:"rp-actionbar",role:"region","aria-label":e,children:[f.jsx("span",{"aria-live":"polite",children:t}),f.jsx("div",{className:"rp-toolbar",children:r})]})}function xn({className:e,...t}){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:12,height:12,viewBox:"0 0 12 12","aria-hidden":"true",focusable:"false",className:Ie("rp-icon",e),...t,children:[1.6,6,10.4].flatMap(r=>[3.8,8.2].map(n=>f.jsx("circle",{cx:n,cy:r,r:1.1,fill:"currentColor"},`${n}-${r}`)))})}function wn(e,t){return e.flatMap(r=>{if(r.kind!=="subscription")return[];const n=t.filter(o=>o.provider_id===r.id),a=new Set(n.map(o=>o.subscription_tag).filter(Boolean));return a.size!==1?[]:[{tag:[...a][0],label:r.name,count:n.length}]})}const Ze=6;function Tn(e,t,r,n,a){const o=new Map(Ke(e).map(l=>[l.name,Le(l)])),y=ot(e,t),c=Ke(y),D=new Map(r.map(l=>[l.tag,l])),v=a("arrange.lastMember"),g=c.map(l=>{const d=Le(l),p=o.get(l.name),b=Ve(l.filters),m=d.rules.length?Ve(d.rules):null,E=t.filter(s=>s.group===l.name),T=new Set(E.flatMap(s=>s.kind==="removeNode"?n.filter(u=>u.name===s.value):s.kind==="removeSubscription"?n.filter(u=>u.subscription_tag===s.value):[])),i=m?n.filter(m).map(s=>s.name):[];return{name:l.name,isNew:!p,holdsAll:l.filters.length===0,names:d.names.map(s=>({name:s,isNew:!!p&&!p.names.includes(s),blocked:Ge(l,"name",s)?v:null})),subscriptions:d.subtags.map(s=>({tag:s,label:D.get(s)?.label??s,count:D.get(s)?.count??null,isNew:!!p&&!p.subtags.includes(s),blocked:Ge(l,"subtag",s)?v:null})),rules:d.rules,ruleNote:d.rules.length?a("arrange.ruleNote",{n:d.rules.length}):null,ruleNodes:i.slice(0,Ze),ruleMore:Math.max(0,i.length-Ze),stillIn:[...T].filter(b).map(s=>s.name),removedNames:E.flatMap(s=>s.kind==="removeNode"?[s.value]:[]),removedSubscriptions:E.flatMap(s=>s.kind==="removeSubscription"?[{tag:s.value,label:D.get(s.value)?.label??s.value}]:[])}}),$=new Set(n.map(l=>l.name));return{groups:g,stagedText:y,unknown:new Set(g.flatMap(l=>l.names.filter(d=>!$.has(d.name)).map(d=>d.name))),emptyNew:g.filter(l=>l.isNew&&l.holdsAll).map(l=>l.name)}}function kn(e,t){return t?null:[...e.names,...e.subscriptions].find(r=>r.blocked)?.blocked??null}function Kn(e,t,r){return e??(t.length?r("arrange.emptyNew",{group:t[0]}):null)}function Ft(e,t){return e?t.kind==="node"?e.names.some(r=>r.name===t.value):e.subscriptions.some(r=>r.tag===t.value):!1}function Cn(e){try{const t=JSON.parse(e);if(!t||typeof t!="object")return null;const{kind:r,value:n}=t;return(r==="node"||r==="subscription")&&typeof n=="string"&&n?{kind:r,value:n}:null}catch{return null}}function Fn(e,t,r){const n=a=>t.find(o=>o.tag===a)?.label??a;switch(e.kind){case"addNode":return r("arrange.change.addNode",{name:e.value,group:e.group});case"removeNode":return r("arrange.change.removeNode",{name:e.value,group:e.group});case"addSubscription":return r("arrange.change.addSubscription",{name:n(e.value),group:e.group});case"removeSubscription":return r("arrange.change.removeSubscription",{name:n(e.value),group:e.group});case"createGroup":return r("arrange.change.createGroup",{group:e.group})}}function Te(e,t){const r={addNode:"removeNode",removeNode:"addNode",addSubscription:"removeSubscription",removeSubscription:"addSubscription"};if(t.kind==="createGroup")return e.some(a=>a.kind==="createGroup"&&a.group===t.group)?e:[...e,t];if((t.kind==="addNode"||t.kind==="addSubscription")&&!it(t.value))return e;const n=e.findIndex(a=>a.kind===r[t.kind]&&a.group===t.group&&"value"in a&&a.value===t.value);return n!==-1?e.filter((a,o)=>o!==n):e.some(a=>a.kind===t.kind&&a.group===t.group&&"value"in a&&a.value===t.value)?e:[...e,t]}function Sn(e,t){const r=e[t];return e.filter((n,a)=>a!==t&&!(r.kind==="createGroup"&&n.group===r.group))}const pe="application/x-doona-placeable";function Pn(e){const t=W(),r=ar(),n=r.data?.resources,a=or(He(n,"nodes",{whileLoading:!1})),o=ir(He(n,"providers",{whileLoading:!1})),y=a.data,[c,D]=x.useState([]),v=lr(c.length>0,()=>D([])),g=e.main?.content??"",$=x.useMemo(()=>wn(o.data?.providers??[],y??[]),[o.data,y]),l=x.useMemo(()=>Tn(g,c,$,y??[],t),[g,c,$,y,t]),d=x.useMemo(()=>new Map(l.groups.map(K=>[K.name,K])),[l.groups]),{contains:p}=Br({sensitivity:"base"}),[b,m]=x.useState(""),E=x.useDeferredValue(b).trim(),T=x.useMemo(()=>(y??[]).filter(K=>!E||p(K.name,E)||p(K.protocol??"",E)),[y,E,p]),i=x.useMemo(()=>$.filter(K=>!E||p(K.label,E)),[$,E,p]),[s,u]=x.useState(!1),[h,w]=x.useState(!1),[k,C]=x.useState(null),S=e.writable?e.main?null:"arrange.noMain":"arrange.readOnly",I=K=>{h||(C(null),D(K))},H=(K,A)=>{A.some(O=>!it(O.value))&&ze("negative",t("config.unquotable")),I(O=>A.filter(he=>!Ft(d.get(K),he)).reduce((he,Ne)=>Te(he,{kind:Ne.kind==="node"?"addNode":"addSubscription",group:K,value:Ne.value}),O))},j=(K,A)=>I(O=>Te(O,{kind:A.kind==="node"?"removeNode":"removeSubscription",group:K,value:A.value})),U=new Set(l.groups.map(K=>K.name)),J=K=>Fr(K,U,t),Z=async()=>{w(!0),C(null);try{const K=await e.apply(A=>ot(A,c));K.kind==="invalid"&&C(t("ui.writeInvalid",{n:K.errors})),K.kind==="failed"&&C(t("arrange.failed",{error:ur(K.error,t)})),K.kind==="ok"&&(ze("positive",t("arrange.applied",{n:c.length})),D([]),v.clear(),u(!1))}finally{w(!1)}},X=x.useMemo(()=>{if(!c.length)return[];const K=l.stagedText.split(`
+`),A=new Set(c.map(O=>O.group));return Ke(l.stagedText).filter(O=>A.has(O.name)).map(O=>({group:O.name,text:K.slice(O.from,O.to+1).join(`
+`)}))},[l.stagedText,c]);return{groups:l.groups,unknown:l.unknown,byGroup:d,subscriptions:i,nodes:T,search:b,setSearch:m,loading:r.loading&&!r.data||a.loading&&!y||o.loading&&!o.data,error:[r,a,o].find(K=>K.error&&!K.data)?.error??(e.main?null:e.error),retry:x.useCallback(()=>void sr(),[]),blocked:S?t(S):null,busy:e.busy||h,applying:h,failure:k,changes:c,changeLines:c.map(K=>Fn(K,$,t)),pendingText:t("arrange.pending",{n:c.length}),place:H,unplace:j,drop:K=>I(A=>Sn(A,K)),discard:()=>I(()=>[]),nameProblem:J,create:(K,A)=>I(O=>Te(O,{kind:"createGroup",group:K,policy:A})),reviewing:s&&c.length>0,setReviewing:K=>{h||u(K)},preview:X,canApply:c.length>0&&l.emptyNew.length===0&&!S&&!h,applyNote:Kn(S?t(S):null,l.emptyNew,t),apply:Z}}function Xn({source:e,groups:t}){const r=W(),n=Pn(e),a=x.useMemo(()=>new Map((t??[]).map(o=>[o.name,o])),[t]);return n.error?f.jsx(dr,{error:n.error,onRetry:n.retry}):n.loading?f.jsx(cr,{}):f.jsxs("div",{className:"rp-arrange",children:[f.jsxs("div",{className:"rp-row",children:[f.jsxs("p",{className:"rp-note rp-grow",children:[f.jsx("span",{className:"rp-wide-only",children:r("arrange.note")}),f.jsx("span",{className:"rp-narrow-only",children:r("arrange.selectHint")})]}),f.jsx(An,{m:n})]}),n.blocked&&f.jsx(Q,{tone:"informative",children:n.blocked}),f.jsxs("div",{className:"rp-arrange-grid",children:[f.jsx("div",{className:"rp-col",children:n.groups.length?n.groups.map(o=>f.jsx(Bn,{group:o,live:a.get(o.name),m:n},o.name)):f.jsx(lt,{children:r("policy.empty")})}),f.jsx(In,{m:n})]}),n.changes.length>0&&f.jsxs(En,{label:r("arrange.pendingRegion"),message:n.pendingText,children:[f.jsx(L,{quiet:!0,onPress:n.discard,isDisabled:n.busy,children:r("arrange.discard")}),f.jsx(L,{accent:!0,onPress:()=>n.setReviewing(!0),children:r("arrange.review")})]}),f.jsx(On,{m:n})]})}function Bn({group:e,live:t,m:r}){const n=W(),a=dt(),o=x.useId(),y=!!r.blocked,c=t?Sr(t.policy,n):null,D=async $=>{const l=await Promise.all($.filter(Rr).filter(d=>d.types.has(pe)).map(d=>d.getText(pe)));r.place(e.name,l.flatMap(d=>Cn(d)??[]))},v=($,l,d)=>f.jsx(L,{quiet:!0,icon:!0,small:!0,label:n("arrange.remove",{name:$,group:e.name}),isDisabled:y||r.applying||!!d,onPress:()=>r.unplace(e.name,l),children:f.jsx(ct,{})}),g=($,l)=>f.jsx(L,{quiet:!0,small:!0,label:n("arrange.undoRemove",{name:$}),isDisabled:r.applying,onPress:()=>r.place(e.name,[l]),children:n("arrange.undoShort")});return f.jsx(nn,{className:mr("rp-drop"),"aria-label":n("arrange.dropInto",{group:e.name}),isDisabled:y||r.applying,getDropOperation:$=>$.has(pe)?"copy":"cancel",onDrop:$=>void D($.items),children:({isDropTarget:$})=>f.jsxs(f.Fragment,{children:[f.jsx("div",{className:"rp-row",children:f.jsxs("span",{className:"rp-cluster",children:[f.jsx("h3",{className:"rp-h3",id:o,children:e.name}),c&&f.jsx(Xe,{tip:c.id,children:c.label}),t&&f.jsx(pr,{small:!0,tone:"neutral",children:n("arrange.memberCount",{n:t.member_count})}),e.isNew&&f.jsx(Xe,{children:n("arrange.new")})]})}),e.holdsAll&&f.jsx("p",{className:"rp-note",children:n("arrange.holdsAll")}),f.jsxs(fr,{reason:kn(e,y||r.applying),children:[(e.names.length>0||e.removedNames.length>0)&&f.jsxs(Je,{label:n("arrange.byName"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:n("arrange.byName")}),e.names.map(l=>f.jsx(ue,{tone:l.isNew?"new":void 0,action:v(l.name,{kind:"node",value:l.name},l.blocked),children:l.name},l.name)),e.removedNames.map(l=>f.jsx(ue,{tone:"removed",action:g(l,{kind:"node",value:l}),children:l},l))]}),(e.subscriptions.length>0||e.removedSubscriptions.length>0)&&f.jsxs(Je,{label:n("arrange.bySubscription"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:n("arrange.bySubscription")}),e.subscriptions.map(l=>f.jsx(ue,{tone:l.isNew?"new":void 0,action:v(l.label,{kind:"subscription",value:l.tag},l.blocked),children:l.count===null?l.label:n("arrange.subscriptionCount",{name:l.label,n:l.count})},l.tag)),e.removedSubscriptions.map(l=>f.jsx(ue,{tone:"removed",action:g(l.label,{kind:"subscription",value:l.tag}),children:l.label},l.tag))]})]}),e.rules.length>0&&f.jsxs("div",{className:"rp-arrange-rules",children:[f.jsx("span",{className:"rp-label",children:n("arrange.byRule")}),e.rules.map(l=>f.jsx(pt,{as:"code",text:l},l)),e.ruleNodes.length>0&&f.jsx("span",{children:e.ruleMore?n("arrange.ruleSelectsMore",{names:de(a,e.ruleNodes),n:e.ruleMore}):n("arrange.ruleSelects",{names:de(a,e.ruleNodes)})}),f.jsxs("span",{className:"rp-label",children:[e.ruleNote," ",f.jsx(gr,{appearance:"link",href:yr("config",{tab:"source"}),children:n("arrange.editSource")})]})]}),e.stillIn.length>0&&f.jsx(Q,{tone:"informative",children:n("arrange.stillIn",{names:de(a,e.stillIn)})}),$&&f.jsx("div",{className:"rp-drop-hint","aria-hidden":"true",children:n("arrange.dropHint")})]})})}function In({m:e}){const t=W(),r=x.useId(),n=!!e.blocked||e.applying,[a,o]=x.useState("all"),[y,c]=x.useState(new Set),D=x.useMemo(()=>[...a==="node"?[]:e.subscriptions.map(d=>({id:"subscription:"+d.tag,item:{kind:"subscription",value:d.tag},label:d.label,meta:t("arrange.subscriptionMeta",{n:d.count})})),...a==="subscription"?[]:e.nodes.map(d=>({id:"node:"+d.name,item:{kind:"node",value:d.name},label:d.name,meta:d.protocol??""}))],[a,e.subscriptions,e.nodes,t]),v=x.useMemo(()=>new Map(D.map(d=>[d.id,d])),[D]),g=y==="all"?D:[...y].flatMap(d=>v.get(String(d))??[]),{dragAndDropHooks:$}=vn({getItems:d=>[...d].flatMap(p=>v.has(String(p))?[{[pe]:JSON.stringify(v.get(String(p)).item),"text/plain":v.get(String(p)).label}]:[]),getAllowedDropOperations:()=>["copy"],isDisabled:n}),l=e.groups.filter(d=>g.some(p=>!Ft(d,p.item)));return f.jsxs(hr,{title:t("arrange.tray"),titleId:r,className:"rp-tray",children:[f.jsx(ut,{search:!0,label:t("arrange.search"),value:e.search,onChange:e.setSearch}),f.jsx(Dr,{label:t("arrange.show"),value:a,onChange:d=>o(d),items:[["all",t("ui.all")],["subscription",t("arrange.subscriptions")],["node",t("arrange.nodes")]]}),f.jsx(Kr,{layout:Cr,layoutOptions:{rowHeight:48},children:f.jsx(Tr,{"aria-labelledby":r,className:"rp-tray-list",items:D,selectionMode:"multiple",selectionBehavior:"toggle",selectedKeys:y,onSelectionChange:c,dragAndDropHooks:$,renderEmptyState:()=>f.jsx(lt,{children:t("arrange.trayEmpty")}),children:d=>f.jsxs(kr,{id:d.id,textValue:d.label,className:"rp-item rp-tray-row",children:[f.jsx(br,{slot:"drag",className:Ie($r({quiet:!0,icon:!0,small:!0}),"rp-drag"),"aria-label":t("arrange.drag",{name:d.label}),children:f.jsx(xn,{})}),f.jsx(vr,{}),f.jsxs("span",{className:"rp-grow",children:[f.jsx(Er,{children:d.label}),f.jsx("span",{className:"desc",children:d.meta})]})]})})}),f.jsxs("div",{className:"rp-tray-bar",children:[f.jsx("span",{className:"rp-grow rp-label","aria-live":"polite",children:g.length?t("arrange.selected",{n:g.length}):t("arrange.selectHint")}),g.length>0&&f.jsx(L,{quiet:!0,small:!0,onPress:()=>c(new Set),children:t("arrange.clear")}),f.jsx(xr,{label:t("arrange.addSelected"),isDisabled:n||!l.length,items:l.map(d=>({id:d.name,label:d.name})),onAction:d=>{e.place(d,g.map(p=>p.item)),c(new Set)},children:t("arrange.addSelected")})]})]})}function An({m:e}){const t=W(),r=x.useId(),[n,a]=x.useState(!1),[o,y]=x.useState(""),[c,D]=x.useState(Ue[0].id),[v,g]=x.useState(!1),$=e.nameProblem(o.trim()),l=()=>{y(""),D(Ue[0].id),g(!1)};return f.jsxs(f.Fragment,{children:[f.jsx(L,{small:!0,onPress:()=>a(!0),isDisabled:!!e.blocked||e.applying,children:t("arrange.newGroup")}),f.jsx(st,{title:t("arrange.newGroup"),narrow:!0,isOpen:n,onOpenChange:d=>{a(d),d||l()},footer:d=>f.jsxs(f.Fragment,{children:[f.jsx(L,{onPress:d,children:t("ui.cancel")}),f.jsx(L,{accent:!0,type:"submit",form:r,children:t("arrange.create")})]}),children:f.jsxs("form",{id:r,className:"rp-form",onSubmit:d=>{d.preventDefault(),g(!0),!$&&(e.create(o.trim(),c),a(!1),l())},children:[f.jsx(ut,{label:t("arrange.groupName"),value:o,onChange:y,description:t("arrange.groupNameHint"),error:v&&$?$:void 0,spellCheck:!1}),f.jsx(Pr,{value:c,onChange:D}),f.jsx("p",{className:"rp-label",children:t("arrange.newGroupNote")})]})})]})}function On({m:e}){const t=W(),r=dt();return f.jsxs(st,{title:t("arrange.reviewTitle"),isOpen:e.reviewing,onOpenChange:e.setReviewing,footer:n=>f.jsxs(f.Fragment,{children:[f.jsx(L,{onPress:n,isDisabled:e.applying,children:t("ui.cancel")}),f.jsx(L,{accent:!0,isPending:e.applying,isDisabled:!e.canApply,onPress:()=>void e.apply(),children:t("config.save")})]}),children:[e.failure&&f.jsx(Q,{takeFocus:!0,children:e.failure}),e.applyNote&&f.jsx(Q,{children:e.applyNote}),e.unknown.size>0&&f.jsx(Q,{tone:"informative",children:t("arrange.unknown",{names:de(r,[...e.unknown])})}),f.jsx("ol",{className:"rp-arrange-changes",children:e.changeLines.map((n,a)=>f.jsxs("li",{className:"rp-row",children:[f.jsx("span",{className:"rp-grow",children:n}),f.jsx(L,{quiet:!0,icon:!0,small:!0,label:t("arrange.undo",{change:n}),isDisabled:e.applying,onPress:()=>e.drop(a),children:f.jsx(ct,{})})]},a))}),f.jsx(wr,{title:t("arrange.showText"),children:e.preview.map(n=>f.jsx(pt,{as:"pre",className:"rp-arrange-preview",text:n.text},n.group))}),f.jsx("p",{className:"rp-label",children:t("arrange.applyNote")})]})}export{Xn as Arrange};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-C-Cvg5Lz.js b/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-C-Cvg5Lz.js
deleted file mode 100644
index db246d1db..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Arrange-C-Cvg5Lz.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import{r as x,$ as _,a as Ft,j as f}from"./vendor-react-Bf71BWbF.js";import{ef as Pt,ew as Bt,e9 as ae,bI as G,bG as M,ex as Qe,ey as et,ez as It,bA as Re,e6 as S,e7 as re,e8 as Be,dU as j,el as tt,eA as At,eB as Ot,eC as Mt,bx as Nt,bJ as jt,bQ as Rt,eD as Lt,bS as Vt,bT as Gt,bv as Ht,ed as zt,bV as Ut,bs as Xt,bX as Yt,bZ as qt,bW as _t,eE as Wt,eF as Jt,bt as ke,aA as Zt,ep as Qt,em as er,bF as tr,eG as rt,eH as nt,eI as oe,bu as rr,bq as at,dT as nr,bd as Ie,z as Ke,eJ as Le,cZ as ot,eK as Ve,eL as Ge,d3 as it,u as W,$ as ar,a2 as or,a1 as He,a4 as ir,co as lr,dj as sr,a as ur,b0 as ze,E as dr,b as cr,I as Q,a8 as lt,B as L,cU as Ue,M as st,T as ut,_ as dt,ay as Xe,at as pr,U as de,L as fr,h as gr,bn as yr,ax as mr,aS as hr,eM as Dr,eN as br,eO as $r,av as vr,b9 as Er,a7 as ct,cv as xr}from"./index-zQjLFfuj.js";import{$ as wr,a as Tr}from"./Policies-VixfIaVZ.js";import{d as kr}from"./Virtualizer-CTh266-x.js";import{$ as Kr}from"./ListLayout-DU_9AgrU.js";import{D as pt}from"./DaeCode-B4MDdwFy.js";import{b as Cr,g as Sr}from"./policyText-IIH31itq.js";import{P as Fr}from"./PolicyPicker-iyQz7WhP.js";import{$ as Pr}from"./useFilter-BYneYrGs.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";var P=(function(e){return e[e.none=0]="none",e[e.cancel=0]="cancel",e[e.move=1]="move",e[e.copy=2]="copy",e[e.link=4]="link",e[e.all=7]="all",e})({});const ft={...P,copyMove:3,copyLink:6,linkMove:5,all:7,uninitialized:7},gt=yt(ft);gt[7]="all";const ee={none:"cancel",link:"link",copy:"copy",move:"move"},De=yt(ee);function yt(e){let t={};for(let n in e)t[e[n]]=n;return t}const Br=new Set(["text/plain","text/uri-list","text/html"]),fe="application/vnd.react-aria.items+json",ge="application/octet-stream",Ae=new WeakMap,mt=Symbol();function Ir(e){let{id:t}=Ae.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function Ar(e){let{ref:t}=Ae.get(e)||{};if(!t)throw new Error("Droppable item outside a droppable collection");return t}function z(e){let t=new Set;for(let n of e)for(let r of Object.keys(n))t.add(r);return t}function ht(e){return e||(e="virtual"),e==="pointer"&&(e="virtual"),e==="virtual"&&typeof window<"u"&&typeof window.matchMedia=="function"&&window.matchMedia("(pointer: coarse)").matches&&(e="touch"),e}function Oe(){return ht(Pt())}function Dt(){return ht(Bt())}function Ce(e,t){let n=new Map,r=!1,a=[];for(let o of t){let y=Object.keys(o);y.length>1&&(r=!0);let c={};for(let D of y){let v=n.get(D);v?r=!0:(v=[],n.set(D,v));let g=o[D];c[D]=g,v.push(g)}a.push(c)}for(let[o,y]of n)if(Br.has(o)){let c=y.join(`
-`);e.items.add(c,o)}else e.items.add(y[0],o);if(r){let o=JSON.stringify(a);e.items.add(o,fe)}}class ie{constructor(t){this.types=new Set;let n=!1;for(let r of t.items)r.type!==fe&&(r.kind==="file"&&(n=!0),r.type?this.types.add(r.type):this.types.add(ge));this.includesUnknownTypes=!n&&t.types.includes("Files")}has(t){if(Array.isArray(t))return t.some(n=>this.has(n));if(this.includesUnknownTypes||t===mt&&this.types.has(ge)||t==="*/*")return!0;if(typeof t=="string"){if(t.endsWith("/*")){for(let n of this.types)if(n.startsWith(t.slice(0,-2)))return!0;return!1}return this.types.has(t)}return!1}}function bt(e){let t=[];if(!e)return t;let n=!1;if(e.types.includes(fe))try{let r=e.getData(fe),a=JSON.parse(r);for(let o of a)t.push({kind:"text",types:new Set(Object.keys(o)),getText:y=>Promise.resolve(o[y])});n=!0}catch{}if(!n){let r=new Map;for(let a of e.items)if(a.kind==="string")r.set(a.type||ge,e.getData(a.type));else if(a.kind==="file")if(typeof a.webkitGetAsEntry=="function"){let o=a.webkitGetAsEntry();if(!o)continue;o.isFile?t.push(Se(a.getAsFile())):o.isDirectory&&t.push($t(o))}else t.push(Se(a.getAsFile()));r.size>0&&t.push({kind:"text",types:new Set(r.keys()),getText:a=>Promise.resolve(r.get(a))})}return t}function Or(e){return typeof e.text=="function"?e.text():new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{t(r.result)},r.onerror=n,r.readAsText(e)})}function Se(e){if(!e)throw new Error("No file provided");return{kind:"file",type:e.type||ge,name:e.name,getText:()=>Or(e),getFile:()=>Promise.resolve(e)}}function $t(e){return{kind:"directory",name:e.name,getEntries:()=>Mr(e)}}async function*Mr(e){let t=e.createReader(),n;do{n=await new Promise((r,a)=>{t.readEntries(r,a)});for(let r of n)if(r.isFile){let a=await Nr(r);yield Se(a)}else r.isDirectory&&(yield $t(r))}while(n.length>0)}function Nr(e){return new Promise((t,n)=>e.file(t,n))}function jr(e){return e.kind==="text"}let B={draggingKeys:new Set};function Rr(e){B.draggingCollectionRef=e}function Lr(e){B.draggingKeys=e}function Y(e){B.dropCollectionRef=e}function vt(){B={draggingKeys:new Set}}function Vr(e){B=e}function V(e){let{draggingCollectionRef:t,dropCollectionRef:n}=B;return t?.current!=null&&t.current===(e?.current||n?.current)}let ce;function ye(e){ce=e}let Fe=P.none;function be(e){Fe=e}let Pe=new Map,te=new Map,R=null,me=new Set;function Et(e){return Pe.set(e.element,e),R?.updateValidDropTargets(),()=>{Pe.delete(e.element),R?.updateValidDropTargets()}}function Gr(e){return te.set(e.element,e),()=>{te.delete(e.element)}}function Hr(e,t){if(R)throw new Error("Cannot begin dragging while already dragging");R=new qr(e,t),requestAnimationFrame(()=>{R&&(R.setup(),Dt()==="keyboard"&&R.next())});for(let n of me)n()}function Me(){let[e,t]=x.useState(R);return x.useEffect(()=>{let n=()=>t(R);return me.add(n),()=>{me.delete(n)}},[]),e}function zr(){return!!R}function Ur(){R=null;for(let e of me)e()}const Ye=["pointerdown","pointermove","pointerenter","pointerleave","pointerover","pointerout","pointerup","mousedown","mousemove","mouseenter","mouseleave","mouseover","mouseout","mouseup","touchstart","touchmove","touchend","focusin","focusout"],Xr=["pointerup","mouseup","touchend"],Yr={keyboard:"dragStartedKeyboard",touch:"dragStartedTouch",virtual:"dragStartedVirtual"};class qr{constructor(t,n){this.validDropTargets=[],this.currentDropTarget=null,this.currentDropItem=null,this.dropOperation=null,this.mutationObserver=null,this.restoreAriaHidden=null,this.isVirtualClick=!1,this.dragTarget=t,this.stringFormatter=n,this.onKeyDown=this.onKeyDown.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onFocus=this.onFocus.bind(this),this.onBlur=this.onBlur.bind(this),this.onClick=this.onClick.bind(this),this.onPointerDown=this.onPointerDown.bind(this),this.cancelEvent=this.cancelEvent.bind(this),this.initialFocused=!1}setup(){document.addEventListener("keydown",this.onKeyDown,!0),document.addEventListener("keyup",this.onKeyUp,!0),window.addEventListener("focus",this.onFocus,!0),window.addEventListener("blur",this.onBlur,!0),document.addEventListener("click",this.onClick,!0),document.addEventListener("pointerdown",this.onPointerDown,!0);for(let t of Ye)document.addEventListener(t,this.cancelEvent,!0);this.mutationObserver=new MutationObserver(()=>this.updateValidDropTargets()),this.updateValidDropTargets(),ae(this.stringFormatter.format(Yr[Dt()]))}teardown(){document.removeEventListener("keydown",this.onKeyDown,!0),document.removeEventListener("keyup",this.onKeyUp,!0),window.removeEventListener("focus",this.onFocus,!0),window.removeEventListener("blur",this.onBlur,!0),document.removeEventListener("click",this.onClick,!0),document.removeEventListener("pointerdown",this.onPointerDown,!0);for(let t of Ye)document.removeEventListener(t,this.cancelEvent,!0);this.mutationObserver?.disconnect(),this.restoreAriaHidden?.()}onKeyDown(t){if(this.cancelEvent(t),t.key==="Escape"){this.cancel();return}t.key==="Tab"&&!(t.metaKey||t.altKey||t.ctrlKey)&&(t.shiftKey?this.previous():this.next()),typeof this.currentDropTarget?.onKeyDown=="function"&&this.currentDropTarget.onKeyDown(t,this.dragTarget)}onKeyUp(t){this.cancelEvent(t),t.key==="Enter"&&(t.altKey||G(this.getCurrentActivateButton(),M(t))?this.activate(this.currentDropTarget,this.currentDropItem):this.drop())}getCurrentActivateButton(){return this.currentDropItem?.activateButtonRef?.current??this.currentDropTarget?.activateButtonRef?.current??null}onFocus(t){let n=this.getCurrentActivateButton(),r=M(t);if(r===n){this.cancelEvent(t);return}if(r!==this.dragTarget.element&&this.cancelEvent(t),!(r instanceof HTMLElement)||r===this.dragTarget.element)return;let a=this.validDropTargets.find(y=>y.element===r)||this.validDropTargets.find(y=>G(y.element,r));if(!a){this.currentDropTarget?this.currentDropTarget.element.focus():this.dragTarget.element.focus();return}let o=te.get(r);a&&this.setCurrentDropTarget(a,o)}onBlur(t){let n=this.getCurrentActivateButton();if(n&&t.relatedTarget===n){this.cancelEvent(t);return}M(t)!==this.dragTarget.element&&this.cancelEvent(t),(!t.relatedTarget||!(t.relatedTarget instanceof HTMLElement))&&(this.currentDropTarget?this.currentDropTarget.element.focus():this.dragTarget.element.focus())}onClick(t){if(this.cancelEvent(t),Qe(t)||this.isVirtualClick){let n=te.values(),r=M(t),a=[...n].find(c=>c.element===r||G(c.activateButtonRef?.current,r)),o=this.validDropTargets.find(c=>G(c.element,r)),y=a?.activateButtonRef?.current??o?.activateButtonRef?.current;if(G(y,r)&&o){this.activate(o,a);return}if(M(t)===this.dragTarget.element){this.cancel();return}o&&(this.setCurrentDropTarget(o,a),this.drop(a))}}onPointerDown(t){this.cancelEvent(t),this.isVirtualClick=et(t)}cancelEvent(t){let n=M(t);(t.type==="focusin"||t.type==="focusout")&&(n===this.dragTarget?.element||n===this.getCurrentActivateButton())||(Xr.includes(t.type)||t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation())}updateValidDropTargets(){if(!this.mutationObserver)return;if(this.mutationObserver.disconnect(),this.restoreAriaHidden&&this.restoreAriaHidden(),this.validDropTargets=_r(this.dragTarget),this.validDropTargets.length>0){let a=this.findNearestDropTarget();this.validDropTargets=[...this.validDropTargets.slice(a),...this.validDropTargets.slice(0,a)]}this.currentDropTarget&&!this.validDropTargets.includes(this.currentDropTarget)&&this.setCurrentDropTarget(this.validDropTargets[0]);let t=z(this.dragTarget.items),n=[...te.values()].filter(a=>typeof a.getDropOperation=="function"?a.getDropOperation(t,this.dragTarget.allowedDropOperations)!=="cancel":!0),r=this.validDropTargets.filter(a=>!n.some(o=>G(a.element,o.element)));this.restoreAriaHidden=It([this.dragTarget.element,...n.flatMap(a=>a.activateButtonRef?.current?[a.element,a.activateButtonRef?.current]:[a.element]),...r.flatMap(a=>a.activateButtonRef?.current?[a.element,a.activateButtonRef?.current]:[a.element])],{shouldUseInert:!0}),this.mutationObserver.observe(document.body,{subtree:!0,attributes:!0,attributeFilter:["aria-hidden","inert"]})}next(){if(!this.currentDropTarget){this.setCurrentDropTarget(this.validDropTargets[0]);return}let t=this.validDropTargets.indexOf(this.currentDropTarget);if(t<0){this.setCurrentDropTarget(this.validDropTargets[0]);return}t===this.validDropTargets.length-1?this.dragTarget.element.closest('[aria-hidden="true"], [inert]')?this.setCurrentDropTarget(this.validDropTargets[0]):(this.setCurrentDropTarget(null),this.dragTarget.element.focus()):this.setCurrentDropTarget(this.validDropTargets[t+1])}previous(){if(!this.currentDropTarget){this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]);return}let t=this.validDropTargets.indexOf(this.currentDropTarget);if(t<0){this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]);return}t===0?this.dragTarget.element.closest('[aria-hidden="true"], [inert]')?this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length-1]):(this.setCurrentDropTarget(null),this.dragTarget.element.focus()):this.setCurrentDropTarget(this.validDropTargets[t-1])}findNearestDropTarget(){let t=this.dragTarget.element.getBoundingClientRect(),n=1/0,r=-1,a=-1;for(let o=0;o=0?a:r}setCurrentDropTarget(t,n){if(t!==this.currentDropTarget){if(this.currentDropTarget&&typeof this.currentDropTarget.onDropExit=="function"){let r=this.currentDropTarget.element.getBoundingClientRect();this.currentDropTarget.onDropExit({type:"dropexit",x:r.left+r.width/2,y:r.top+r.height/2})}if(this.currentDropTarget=t,t){if(typeof t.onDropEnter=="function"){let r=t.element.getBoundingClientRect();t.onDropEnter({type:"dropenter",x:r.left+r.width/2,y:r.top+r.height/2},this.dragTarget)}n||t?.element.focus()}}if(n!=null&&n!==this.currentDropItem&&(this.currentDropTarget&&typeof this.currentDropTarget.onDropTargetEnter=="function"&&this.currentDropTarget.onDropTargetEnter(n.target),n.element.focus(),this.currentDropItem=n,!this.initialFocused)){let r=n?.element.getAttribute("aria-label");r&&ae(r,"polite"),this.initialFocused=!0}}end(){if(this.teardown(),Ur(),typeof this.dragTarget.onDragEnd=="function"){let n=(this.currentDropTarget&&this.dropOperation!=="cancel"?this.currentDropTarget:this.dragTarget).element.getBoundingClientRect();this.dragTarget.onDragEnd({type:"dragend",x:n.x+n.width/2,y:n.y+n.height/2,dropOperation:this.dropOperation||"cancel"})}this.currentDropTarget&&!this.currentDropTarget.preventFocusOnDrop&&Re()?.dispatchEvent(new FocusEvent("focusin",{bubbles:!0})),this.setCurrentDropTarget(null)}cancel(){this.setCurrentDropTarget(null),this.end(),this.dragTarget.element.closest('[aria-hidden="true"], [inert]')||this.dragTarget.element.focus(),Re()?.dispatchEvent(new FocusEvent("focusin",{bubbles:!0})),ae(this.stringFormatter.format("dropCanceled"))}drop(t){if(!this.currentDropTarget){this.cancel();return}if(typeof t?.getDropOperation=="function"){let n=z(this.dragTarget.items);this.dropOperation=t.getDropOperation(n,this.dragTarget.allowedDropOperations)}else if(typeof this.currentDropTarget.getDropOperation=="function"){let n=z(this.dragTarget.items);this.dropOperation=this.currentDropTarget.getDropOperation(n,this.dragTarget.allowedDropOperations)}else this.dropOperation=this.dragTarget.allowedDropOperations[0];if(typeof this.currentDropTarget.onDrop=="function"){let n=this.dragTarget.items.map(a=>({kind:"text",types:new Set(Object.keys(a)),getText:o=>Promise.resolve(a[o])})),r=this.currentDropTarget.element.getBoundingClientRect();this.currentDropTarget.onDrop({type:"drop",x:r.left+r.width/2,y:r.top+r.height/2,items:n,dropOperation:this.dropOperation},t?.target??null)}this.end(),ae(this.stringFormatter.format("dropComplete"))}activate(t,n){if(t&&typeof t.onDropActivate=="function"){let r=n?.target??null,a=t.element.getBoundingClientRect();t.onDropActivate({type:"dropactivate",x:a.left+a.width/2,y:a.top+a.height/2},r)}}}function _r(e){let t=z(e.items);return[...Pe.values()].filter(n=>n.element.closest('[aria-hidden="true"], [inert]')?!1:typeof n.getDropOperation=="function"?n.getDropOperation(t,e.allowedDropOperations)!=="cancel":!0)}var xt={};xt={dragItem:e=>`Drag ${e.itemText}`,dragSelectedItems:(e,t)=>`Drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}`,dragDescriptionKeyboard:"Press Enter to start dragging.",dragDescriptionKeyboardAlt:"Press Alt + Enter to start dragging.",dragDescriptionTouch:"Double tap to start dragging.",dragDescriptionVirtual:"Click to start dragging.",dragDescriptionLongPress:"Long press to start dragging.",dragSelectedKeyboard:(e,t)=>`Press Enter to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragSelectedKeyboardAlt:(e,t)=>`Press Alt + Enter to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragSelectedLongPress:(e,t)=>`Long press to drag ${t.plural(e.count,{one:()=>`${t.number(e.count)} selected item`,other:()=>`${t.number(e.count)} selected items`})}.`,dragStartedKeyboard:"Started dragging. Press Tab to navigate to a drop target, then press Enter to drop, or press Escape to cancel.",dragStartedTouch:"Started dragging. Navigate to a drop target, then double tap to drop.",dragStartedVirtual:"Started dragging. Navigate to a drop target, then click or press Enter to drop.",endDragKeyboard:"Dragging. Press Enter to cancel drag.",endDragTouch:"Dragging. Double tap to cancel drag.",endDragVirtual:"Dragging. Click to cancel drag.",dropDescriptionKeyboard:"Press Enter to drop. Press Escape to cancel drag.",dropDescriptionTouch:"Double tap to drop.",dropDescriptionVirtual:"Click to drop.",dropCanceled:"Drop canceled.",dropComplete:"Drop complete.",dropIndicator:"drop indicator",dropOnRoot:"Drop on",dropOnItem:e=>`Drop on ${e.itemText}`,insertBefore:e=>`Insert before ${e.itemText}`,insertBetween:e=>`Insert between ${e.beforeItemText} and ${e.afterItemText}`,insertAfter:e=>`Insert after ${e.itemText}`};var wt={};wt={dragDescriptionKeyboard:"按 Enter 开始拖动。",dragDescriptionKeyboardAlt:"按 Alt + Enter 开始拖动。",dragDescriptionLongPress:"长按以开始拖动。",dragDescriptionTouch:"双击开始拖动。",dragDescriptionVirtual:"单击开始拖动。",dragItem:e=>`拖动 ${e.itemText}`,dragSelectedItems:(e,t)=>`拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 选中项目`,other:()=>`${t.number(e.count)} 选中项目`})}`,dragSelectedKeyboard:(e,t)=>`按 Enter 以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragSelectedKeyboardAlt:(e,t)=>`按 Alt + Enter 以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragSelectedLongPress:(e,t)=>`长按以拖动 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 个选定项`,other:()=>`${t.number(e.count)} 个选定项`})}。`,dragStartedKeyboard:"已开始拖动。按 Tab 导航到放置目标,然后按 Enter 放置或按 Escape 取消。",dragStartedTouch:"已开始拖动。导航到放置目标,然后双击放置。",dragStartedVirtual:"已开始拖动。导航到放置目标,然后单击或按 Enter 放置。",dropCanceled:"放置已取消。",dropComplete:"放置已完成。",dropDescriptionKeyboard:"按 Enter 放置。按 Escape 取消拖动。",dropDescriptionTouch:"双击放置。",dropDescriptionVirtual:"单击放置。",dropIndicator:"放置标记",dropOnItem:e=>`放置于 ${e.itemText}`,dropOnRoot:"放置于",endDragKeyboard:"正在拖动。按 Enter 取消拖动。",endDragTouch:"正在拖动。双击取消拖动。",endDragVirtual:"正在拖动。单击取消拖动。",insertAfter:e=>`插入到 ${e.itemText} 之后`,insertBefore:e=>`插入到 ${e.itemText} 之前`,insertBetween:e=>`插入到 ${e.beforeItemText} 和 ${e.afterItemText} 之间`};var Tt={};Tt={dragDescriptionKeyboard:"按 Enter 鍵以開始拖曳。",dragDescriptionKeyboardAlt:"按 Alt+Enter 鍵以開始拖曳。",dragDescriptionLongPress:"長按以開始拖曳。",dragDescriptionTouch:"輕點兩下以開始拖曳。",dragDescriptionVirtual:"按一下滑鼠以開始拖曳。",dragItem:e=>`拖曳「${e.itemText}」`,dragSelectedItems:(e,t)=>`拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}`,dragSelectedKeyboard:(e,t)=>`按 Enter 鍵以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragSelectedKeyboardAlt:(e,t)=>`按 Alt+Enter 鍵以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragSelectedLongPress:(e,t)=>`長按以拖曳 ${t.plural(e.count,{one:()=>`${t.number(e.count)} 個選定項目`,other:()=>`${t.number(e.count)} 個選定項目`})}。`,dragStartedKeyboard:"已開始拖曳。按 Tab 鍵以瀏覽至放置目標,然後按 Enter 鍵以放置,或按 Escape 鍵以取消。",dragStartedTouch:"已開始拖曳。瀏覽至放置目標,然後輕點兩下以放置。",dragStartedVirtual:"已開始拖曳。瀏覽至放置目標,然後按一下滑鼠或按 Enter 鍵以放置。",dropCanceled:"放置已取消。",dropComplete:"放置已完成。",dropDescriptionKeyboard:"按 Enter 鍵以放置。按 Escape 鍵以取消拖曳。",dropDescriptionTouch:"輕點兩下以放置。",dropDescriptionVirtual:"按一下滑鼠以放置。",dropIndicator:"放置指示器",dropOnItem:e=>`放置在「${e.itemText}」上`,dropOnRoot:"放置在",endDragKeyboard:"拖曳中。按 Enter 鍵以取消拖曳。",endDragTouch:"拖曳中。輕點兩下以取消拖曳。",endDragVirtual:"拖曳中。按一下滑鼠以取消拖曳。",insertAfter:e=>`插入至「${e.itemText}」之後`,insertBefore:e=>`插入至「${e.itemText}」之前`,insertBetween:e=>`插入至「${e.beforeItemText}」和「${e.afterItemText}」之間`};var ne={};ne={"ar-AE":S,"bg-BG":S,"cs-CZ":S,"da-DK":S,"de-DE":S,"el-GR":S,"en-US":xt,"es-ES":S,"et-EE":S,"fi-FI":S,"fr-FR":S,"he-IL":S,"hr-HR":S,"hu-HU":S,"it-IT":S,"ja-JP":S,"ko-KR":S,"lt-LT":S,"lv-LV":S,"nb-NO":S,"nl-NL":S,"pl-PL":S,"pt-BR":S,"pt-PT":S,"ro-RO":S,"ru-RU":S,"sk-SK":S,"sl-SI":S,"sr-SP":S,"sv-SE":S,"tr-TR":S,"uk-UA":S,"zh-CN":wt,"zh-TW":Tt};function Wr(e){return e&&e.__esModule?e.default:e}const Jr={keyboard:"dropDescriptionKeyboard",touch:"dropDescriptionTouch",virtual:"dropDescriptionVirtual"};function kt(){let e=re(Wr(ne),"@react-aria/dnd"),t=Oe(),n=Me();return{dropProps:{...Be(n?e.format(Jr[t]):""),onClick:()=>{}}}}const Zr=800;function Kt(e){let{hasDropButton:t,isDisabled:n}=e,[r,a]=x.useState(!1),o=x.useRef({x:0,y:0,dragOverElements:new Set,dropEffect:"none",allowedOperations:P.all,dropActivateTimer:void 0}).current,y=i=>{if(a(!0),typeof e.onDropEnter=="function"){let s=i.currentTarget.getBoundingClientRect();e.onDropEnter({type:"dropenter",x:i.clientX-s.x,y:i.clientY-s.y})}},c=i=>{if(a(!1),typeof e.onDropExit=="function"){let s=i.currentTarget.getBoundingClientRect();e.onDropExit({type:"dropexit",x:i.clientX-s.x,y:i.clientY-s.y})}},D=i=>{i.preventDefault(),i.stopPropagation();let s=qe(i);if(i.clientX===o.x&&i.clientY===o.y&&s===o.allowedOperations){i.dataTransfer.dropEffect=o.dropEffect;return}o.x=i.clientX,o.y=i.clientY;let u=o.dropEffect;if(s!==o.allowedOperations){let h=$e(s),w=h[0];if(typeof e.getDropOperation=="function"){let k=new ie(i.dataTransfer);w=le(s,e.getDropOperation(k,h))}o.dropEffect=De[w]||"none"}if(typeof e.getDropOperationForPoint=="function"){let h=new ie(i.dataTransfer),w=i.currentTarget.getBoundingClientRect(),k=le(s,e.getDropOperationForPoint(h,$e(s),o.x-w.x,o.y-w.y));o.dropEffect=De[k]||"none"}if(o.allowedOperations=s,i.dataTransfer.dropEffect=o.dropEffect,o.dropEffect==="none"&&u!=="none"?c(i):o.dropEffect!=="none"&&u==="none"&&y(i),typeof e.onDropMove=="function"&&o.dropEffect!=="none"){let h=i.currentTarget.getBoundingClientRect();e.onDropMove({type:"dropmove",x:o.x-h.x,y:o.y-h.y})}if(clearTimeout(o.dropActivateTimer),e.onDropActivate&&typeof e.onDropActivate=="function"&&o.dropEffect!=="none"){let h=e.onDropActivate,w=i.currentTarget.getBoundingClientRect();o.dropActivateTimer=setTimeout(()=>{h({type:"dropactivate",x:o.x-w.x,y:o.y-w.y})},Zr)}},v=i=>{if(i.preventDefault(),i.stopPropagation(),o.dragOverElements.add(M(i)),o.dragOverElements.size>1)return;let s=qe(i),u=$e(s),h=u[0];if(typeof e.getDropOperation=="function"){let w=new ie(i.dataTransfer);h=le(s,e.getDropOperation(w,u))}if(typeof e.getDropOperationForPoint=="function"){let w=new ie(i.dataTransfer),k=i.currentTarget.getBoundingClientRect();h=le(s,e.getDropOperationForPoint(w,u,i.clientX-k.x,i.clientY-k.y))}o.x=i.clientX,o.y=i.clientY,o.allowedOperations=s,o.dropEffect=De[h]||"none",i.dataTransfer.dropEffect=o.dropEffect,h!=="cancel"&&y(i)},g=i=>{i.preventDefault(),i.stopPropagation();let s=M(i);if(o.dragOverElements.delete(s),s===i.currentTarget)for(let u of o.dragOverElements)G(i.currentTarget,u)||o.dragOverElements.delete(u);o.dragOverElements.size>0||(o.dropEffect!=="none"&&c(i),clearTimeout(o.dropActivateTimer))},$=i=>{if(i.preventDefault(),i.stopPropagation(),ye(o.dropEffect),typeof e.onDrop=="function"){let u=ee[o.dropEffect],h=bt(i.dataTransfer),w=i.currentTarget.getBoundingClientRect(),k={type:"drop",x:i.clientX-w.x,y:i.clientY-w.y,items:h,dropOperation:u};e.onDrop(k)}let s={...B};o.dragOverElements.clear(),c(i),clearTimeout(o.dropActivateTimer),s.draggingCollectionRef==null?ye(void 0):Vr(s)},l=j(i=>{typeof e.onDropEnter=="function"&&e.onDropEnter(i)}),d=j(i=>{typeof e.onDropExit=="function"&&e.onDropExit(i)}),p=j(i=>{typeof e.onDropActivate=="function"&&e.onDropActivate(i)}),b=j(i=>{typeof e.onDrop=="function"&&e.onDrop(i)}),m=j((i,s)=>e.getDropOperation?e.getDropOperation(i,s):s[0]),{ref:E}=e;tt(()=>{if(!(n||!E.current))return Et({element:E.current,getDropOperation:m,onDropEnter(i){a(!0),l(i)},onDropExit(i){a(!1),d(i)},onDrop:b,onDropActivate:p})},[n,E]);let{dropProps:T}=kt();return n?{dropProps:{},dropButtonProps:{isDisabled:!0},isDropTarget:!1}:{dropProps:{...!t&&T,onDragEnter:v,onDragOver:D,onDragLeave:g,onDrop:$},dropButtonProps:{...t&&T},isDropTarget:r}}function qe(e){let t=ft[e.dataTransfer.effectAllowed];Fe&&(t&=Fe);let n=P.none;return At()?(e.altKey&&(n|=P.copy),e.ctrlKey&&!Ot()&&(n|=P.link),e.metaKey&&(n|=P.move)):(e.altKey&&(n|=P.link),e.shiftKey&&(n|=P.move),e.ctrlKey&&(n|=P.copy)),n?t&n:t}function $e(e){let t=[];return e&P.move&&t.push("move"),e&P.copy&&t.push("copy"),e&P.link&&t.push("link"),t}function le(e,t){let n=P[t];return e&n?t:"cancel"}const ve=new Map;function q(e,t){let n=ve.get(e);if(!n){let r=new Set,a=o=>{for(let y of r)y(o)};n={listener:a,handlers:r},ve.set(e,n),document.addEventListener(e,a)}return n.handlers.add(t),()=>{n.handlers.delete(t),n.handlers.size===0&&(document.removeEventListener(e,n.listener),ve.delete(e))}}function Qr(e){let{isDisabled:t}=e,n=x.useRef(!1),{focusProps:r}=Mt({onFocusChange:g=>{n.current=g}}),a=j(g=>{n.current&&e.getItems&&g.preventDefault()}),o=j(g=>{!n.current||!e.getItems||(g.preventDefault(),g.clipboardData&&(Ce(g.clipboardData,e.getItems({action:"copy"})),e.onCopy?.()))}),y=j(g=>{n.current&&e.onCut&&e.getItems&&g.preventDefault()}),c=j(g=>{!n.current||!e.onCut||!e.getItems||(g.preventDefault(),g.clipboardData&&(Ce(g.clipboardData,e.getItems({action:"cut"})),e.onCut()))}),D=j(g=>{n.current&&e.onPaste&&g.preventDefault()}),v=j(g=>{if(!(!n.current||!e.onPaste)&&(g.preventDefault(),g.clipboardData)){let $=bt(g.clipboardData);e.onPaste($)}});return x.useEffect(()=>{if(!t)return Nt(q("beforecopy",a),q("copy",o),q("beforecut",y),q("cut",c),q("beforepaste",D),q("paste",v))},[t]),{clipboardProps:r}}function en(e){return e&&e.__esModule?e.default:e}const tn=x.createContext(null),rn=x.forwardRef(function(t,n){let{isDisabled:r=!1}=t;[t,n]=jt(t,n,tn);let a=Rt(n),o=x.useRef(null),{dropProps:y,dropButtonProps:c,isDropTarget:D}=Kt({...t,ref:o,hasDropButton:!0}),{buttonProps:v}=Lt(c||{},o),{hoverProps:g,isHovered:$}=Vt(t),{focusProps:l,isFocused:d,isFocusVisible:p}=Gt(),b=re(en(Qt),"react-aria-components"),m=Ht(),E=t["aria-label"]||b.format("dropzoneLabel"),T=t["aria-labelledby"],i=[m,T].filter(Boolean).join(" "),s=zt({"aria-label":E,"aria-labelledby":i}),{clipboardProps:u}=Qr({isDisabled:r,onPaste:k=>t.onDrop?.({type:"drop",items:k,x:0,y:0,dropOperation:"copy"})}),h=Ut({...t,values:{isHovered:$,isFocused:d,isFocusVisible:p,isDropTarget:D,isDisabled:r},defaultClassName:"react-aria-DropZone"}),w=Xt(t,{global:!0});return delete w.id,_.createElement(Yt,{values:[[qt,{id:m,slot:"label"}]]},_.createElement(_t.div,{...ke(w,h,y,g),slot:t.slot||void 0,ref:a,onClick:k=>{let C=M(k);for(;C&&G(a.current,C)&&!Wt(C);){if(C===a.current&&o.current){Jt(o.current);break}C=C.parentElement}},"data-hovered":$||void 0,"data-focused":d||void 0,"data-focus-visible":p||void 0,"data-drop-target":D||void 0,"data-disabled":r||void 0},_.createElement(Zt,null,_.createElement("button",{...ke(v,l,u,s),ref:o})),h.children))});function nn(e,t,n,r,a=!1,o=!1){switch(r){case"left":return a?Ee(e,t,n,o,"left"):xe(e,t,n,o,"left");case"right":return a?xe(e,t,n,o,"right"):Ee(e,t,n,o,"right");case"up":return xe(e,t,n,o);case"down":return Ee(e,t,n,o)}}function Ee(e,t,n,r=!1,a=null){if(!n)return{type:"root"};if(n.type==="root"){let o=e.getFirstKey?.()??null;return o!=null?{type:"item",key:o,dropPosition:"before"}:null}if(n.type==="item"){let o=null;a?o=a==="right"?e.getKeyRightOf?.(n.key,{includeDisabled:!0}):e.getKeyLeftOf?.(n.key,{includeDisabled:!0}):o=e.getKeyBelow?.(n.key,{includeDisabled:!0});let y=Ne(t,n.key,c=>t.getKeyAfter(c));if(o!=null&&o!==y)return{type:"item",key:o,dropPosition:n.dropPosition};switch(n.dropPosition){case"before":return{type:"item",key:n.key,dropPosition:"on"};case"on":{let c=t.getItem(n.key),D=o!=null?t.getItem(o):null;return c&&D&&D.level>=c.level?{type:"item",key:D.key,dropPosition:"before"}:{type:"item",key:n.key,dropPosition:"after"}}case"after":{let c=t.getItem(n.key),D=c?.nextKey!=null?t.getItem(c.nextKey):null;for(;D!=null&&D.type!=="item";)D=D.nextKey!=null?t.getItem(D.nextKey):null;if(c&&D==null&&c.parentKey!=null){let v=t.getItem(c.parentKey);const g=v?.nextKey!=null?t.getItem(v.nextKey):null;if(g?.type==="item")return{type:"item",key:g.key,dropPosition:"before"};if(v?.type==="item")return{type:"item",key:v.key,dropPosition:"after"}}if(D)return{type:"item",key:D.key,dropPosition:"on"}}}}return r?{type:"root"}:null}function xe(e,t,n,r=!1,a=null){if(!n||r&&n.type==="root"){let o=null,y=e.getLastKey?.();for(;y!=null;){let c=t.getItem(y);if(c?.type!=="item")break;o=y,y=c?.parentKey}return o!=null?{type:"item",key:o,dropPosition:"after"}:null}if(n.type==="item"){let o=null;a?o=a==="left"?e.getKeyLeftOf?.(n.key,{includeDisabled:!0}):e.getKeyRightOf?.(n.key,{includeDisabled:!0}):o=e.getKeyAbove?.(n.key,{includeDisabled:!0});let y=Ne(t,n.key,c=>t.getKeyBefore(c));if(o!=null&&o!==y)return{type:"item",key:o,dropPosition:n.dropPosition};switch(n.dropPosition){case"before":{let c=t.getItem(n.key);if(c&&c.prevKey!=null){let D=_e(t,c.prevKey);if(D)return D}return o!=null?{type:"item",key:o,dropPosition:"on"}:{type:"root"}}case"on":return{type:"item",key:n.key,dropPosition:"before"};case"after":{let c=_e(t,n.key);return c||{type:"item",key:n.key,dropPosition:"on"}}}}return n.type!=="root"?{type:"root"}:null}function _e(e,t){let n=e.getItem(t),r=Ne(e,t,o=>e.getKeyAfter(o)),a=r!=null?e.getItem(r):null;if(n&&a&&a.level>n.level){let o=null;if("lastChildKey"in n)for(o=n.lastChildKey!=null?e.getItem(n.lastChildKey):null;o&&o.type!=="item"&&o.prevKey!=null;)o=e.getItem(o.prevKey);else o=Array.from(n.childNodes).findLast(y=>y.type==="item")||null;if(o)return{type:"item",key:o.key,dropPosition:"after"}}return null}function Ne(e,t,n){let r=n(t),a=r!=null?e.getItem(r):null;for(;a&&a.type!=="item";)r=n(a.key),a=r!=null?e.getItem(r):null;return r}const se=20;function an(e){let t=x.useRef(null),n=x.useRef(!0),r=x.useRef(!0);x.useEffect(()=>{if(e.current){t.current=er(e.current)?e.current:tr(e.current);let y=window.getComputedStyle(t.current);n.current=/(auto|scroll)/.test(y.overflowX),r.current=/(auto|scroll)/.test(y.overflowY)}},[e]);let a=x.useRef({timer:void 0,dx:0,dy:0}).current;x.useEffect(()=>()=>{a.timer&&(cancelAnimationFrame(a.timer),a.timer=void 0)},[a]);let o=x.useCallback(()=>{n.current&&t.current&&(t.current.scrollLeft+=a.dx),r.current&&t.current&&(t.current.scrollTop+=a.dy),a.timer&&(a.timer=requestAnimationFrame(o))},[t,a]);return{move(y,c){if(!rt()||nt()||!t.current)return;let D=t.current.getBoundingClientRect(),v=se,g=se,$=D.height-se,l=D.width-se;yl||c$?(yl&&(a.dx=y-l),c$&&(a.dy=c-$),a.timer||(a.timer=requestAnimationFrame(o))):this.stop()},stop(){a.timer&&(cancelAnimationFrame(a.timer),a.timer=void 0)}}}function on(e,t,n){let r=x.useRef({props:e,state:t,nextTarget:null,dropOperation:null}).current;r.props=e,r.state=t;let a=x.useCallback(async l=>{let{onInsert:d,onRootDrop:p,onItemDrop:b,onReorder:m,onMove:E,acceptedDragTypes:T="all",shouldAcceptItemDrop:i}=r.props,{draggingKeys:s}=B,u=V(n),{target:h,dropOperation:w,items:k}=l,C=k;(T!=="all"||i)&&(C=k.filter(F=>{let I;return F.kind==="directory"?I=new Set([mt]):I=F.kind==="file"?new Set([F.type]):F.types,T==="all"||T.some(H=>I.has(H))?h.type==="item"&&h.dropPosition==="on"&&i?i(h,I):!0:!1})),C.length>0&&(h.type==="root"&&p&&await p({items:C,dropOperation:w}),h.type==="item"&&(h.dropPosition==="on"&&b&&await b({items:C,dropOperation:w,isInternal:u,target:h}),E&&u&&await E({keys:s,dropOperation:w,target:h}),h.dropPosition!=="on"&&(!u&&d&&await d({items:C,dropOperation:w,target:h}),u&&m&&await m({keys:s,dropOperation:w,target:h}))))},[r,n]),o=an(n),{dropProps:y}=Kt({ref:n,onDropEnter(){r.nextTarget!=null&&t.setTarget(r.nextTarget)},onDropMove(l){r.nextTarget!=null&&t.setTarget(r.nextTarget),o.move(l.x,l.y)},getDropOperationForPoint(l,d,p,b){let{draggingKeys:m,dropCollectionRef:E}=B,T=V(n),i=u=>t.getDropOperation({target:u,types:l,allowedOperations:d,isInternal:T,draggingKeys:m})!=="cancel",s=e.dropTargetDelegate.getDropTargetFromPoint(p,b,i);if(!s)return r.dropOperation="cancel",r.nextTarget=null,"cancel";if(r.dropOperation=t.getDropOperation({target:s,types:l,allowedOperations:d,isInternal:T,draggingKeys:m}),r.dropOperation==="cancel"){let u={type:"root"},h=t.getDropOperation({target:u,types:l,allowedOperations:d,isInternal:T,draggingKeys:m});h!=="cancel"&&(s=u,r.dropOperation=h)}return s&&r.dropOperation!=="cancel"&&n?.current!==E?.current&&Y(n),r.nextTarget=r.dropOperation==="cancel"?null:s,r.dropOperation},onDropExit(){Y(void 0),t.setTarget(null),o.stop()},onDropActivate(l){t.target?.type==="item"&&typeof e.onDropActivate=="function"&&e.onDropActivate({type:"dropactivate",x:l.x,y:l.y,target:t.target})},onDrop(l){Y(n),t.target&&v(l,t.target);let{draggingCollectionRef:d}=B;d==null&&vt()}}),c=x.useRef(null),D=x.useCallback(()=>{let{state:l}=r;if(c.current){let{target:d,collection:p,selectedKeys:b,focusedKey:m,isInternal:E,draggingKeys:T}=c.current;if(l.collection.size>p.size&&l.selectionManager.isSelectionEqual(b)){let i=new Set,s=l.collection.getFirstKey();for(;s!=null;){let u=l.collection.getItem(s);u?.type==="item"&&!p.getItem(u.key)&&i.add(u.key),u?.hasChildNodes&&l.collection.getItem(u.lastChildKey)?.type==="item"?s=u.firstChildKey:s=l.collection.getKeyAfter(s)}if(l.selectionManager.setSelectedKeys(i),l.selectionManager.focusedKey===m){let u=i.keys().next().value;if(u!=null){let h=l.collection.getItem(u),w=c.current.target,k=l.collection.expandedKeys?l.collection.expandedKeys.has(h?.parentKey):!1;h&&(h?.type==="cell"||w.type==="item"&&w.dropPosition==="on"&&!k)&&(u=h.parentKey),u!=null&&l.selectionManager.setFocusedKey(u),l.selectionManager.selectionMode==="none"&&oe("keyboard")}}}else m!=null&&l.selectionManager.focusedKey===m&&E&&d.type==="item"&&d.dropPosition!=="on"&&T.has(l.collection.getItem(m)?.parentKey)?(l.selectionManager.setFocusedKey(l.collection.getItem(m)?.parentKey??null),oe("keyboard")):l.selectionManager.focusedKey===m&&d.type==="item"&&d.dropPosition==="on"&&l.collection.getItem(d.key)!=null?(l.selectionManager.setFocusedKey(d.key),oe("keyboard")):l.selectionManager.focusedKey!=null&&!l.selectionManager.isSelected(l.selectionManager.focusedKey)&&oe("keyboard");l.selectionManager.setFocused(!0)}},[r]),v=x.useCallback((l,d)=>{let{state:p}=r;c.current={timeout:void 0,focusedKey:p.selectionManager.focusedKey,collection:p.collection,selectedKeys:p.selectionManager.selectedKeys,draggingKeys:B.draggingKeys,isInternal:V(n),target:d},(r.props.onDrop||a)({type:"drop",x:l.x,y:l.y,target:d,items:l.items,dropOperation:l.dropOperation}),c.current.timeout=setTimeout(()=>{D(),c.current=null},50)},[r,a,n,D]);x.useEffect(()=>()=>{c.current&&clearTimeout(c.current.timeout)},[]),tt(()=>{c.current&&t.collection!==c.current.collection&&D()});let{direction:g}=rr();x.useEffect(()=>{if(!n.current)return;let l=(b,m=!0,E="down")=>nn(r.props.keyboardDelegate,r.state.collection,b,E,g==="rtl",m),d=(b,m=!0)=>l(b,m,"up"),p=(b,m,E,T,i=!0)=>{let s=0,u,{draggingKeys:h}=B,w=V(n);do{let k=T(b,i);if(!k)return null;b=k,u=r.state.getDropOperation({target:k,types:m,allowedOperations:E,isInternal:w,draggingKeys:h}),b.type==="root"&&s++}while(u==="cancel"&&!r.state.isDropTarget(b)&&s<2);return u==="cancel"?null:b};return Et({element:n.current,preventFocusOnDrop:!0,getDropOperation(b,m){if(r.state.target){let{draggingKeys:T}=B,i=V(n);return r.state.getDropOperation({target:r.state.target,types:b,allowedOperations:m,isInternal:i,draggingKeys:T})}return p(null,b,m,l)?"move":"cancel"},onDropEnter(b,m){let E=z(m.items),T=r.state.selectionManager,i=null;Y(n);let s=T.focusedKey,u="after",h=s!=null?r.state.collection.getItem(s):null;if(h?.type==="cell"&&(s=h.parentKey),s!=null&&T.isSelected(s)&&(T.selectedKeys.size>1&&T.firstSelectedKey===s?u="before":s=T.lastSelectedKey),s!=null){i={type:"item",key:s,dropPosition:u};let{draggingKeys:w}=B,k=V(n);r.state.getDropOperation({target:i,types:E,allowedOperations:m.allowedDropOperations,isInternal:k,draggingKeys:w})==="cancel"&&(i=p(i,E,m.allowedDropOperations,l,!1)??p(i,E,m.allowedDropOperations,d,!1))}i||(i=p(null,E,m.allowedDropOperations,l)),r.state.setTarget(i)},onDropExit(){Y(void 0),r.state.setTarget(null)},onDropTargetEnter(b){r.state.setTarget(b)},onDropActivate(b,m){m?.type==="item"&&m?.dropPosition==="on"&&typeof r.props.onDropActivate=="function"&&r.props.onDropActivate({type:"dropactivate",x:b.x,y:b.y,target:m})},onDrop(b,m){Y(n),r.state.target&&v(b,m||r.state.target)},onKeyDown(b,m){let{keyboardDelegate:E}=r.props,T=z(m.items);switch(b.key){case"ArrowDown":if(E.getKeyBelow){let i=p(r.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"down"));r.state.setTarget(i)}break;case"ArrowUp":if(E.getKeyAbove){let i=p(r.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"up"));r.state.setTarget(i)}break;case"ArrowLeft":if(E.getKeyLeftOf){let i=p(r.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"left"));r.state.setTarget(i)}break;case"ArrowRight":if(E.getKeyRightOf){let i=p(r.state.target,T,m.allowedDropOperations,(s,u)=>l(s,u,"right"));r.state.setTarget(i)}break;case"Home":if(E.getFirstKey){let i=p(null,T,m.allowedDropOperations,l);r.state.setTarget(i)}break;case"End":if(E.getLastKey){let i=p(null,T,m.allowedDropOperations,d);r.state.setTarget(i)}break;case"PageDown":if(E.getKeyPageBelow){let i=r.state.target;if(!i)i=p(null,T,m.allowedDropOperations,l);else{let s=E.getFirstKey?.();i.type==="item"&&(s=i.key);let u=null;s!=null&&(u=E.getKeyPageBelow(s));let h=i.type==="item"?i.dropPosition:"after";if((u==null||i.type==="item"&&i.key===E.getLastKey?.())&&(u=E.getLastKey?.()??null,h="after"),u==null)break;i={type:"item",key:u,dropPosition:h};let{draggingCollectionRef:w,draggingKeys:k}=B,C=w?.current===n?.current;r.state.getDropOperation({target:i,types:T,allowedOperations:m.allowedDropOperations,isInternal:C,draggingKeys:k})==="cancel"&&(i=p(i,T,m.allowedDropOperations,l,!1)??p(i,T,m.allowedDropOperations,d,!1))}r.state.setTarget(i??r.state.target)}break;case"PageUp":{if(!E.getKeyPageAbove)break;let i=r.state.target;if(!i)i=p(null,T,m.allowedDropOperations,d);else if(i.type==="item"){if(i.key===E.getFirstKey?.())i={type:"root"};else{let w=E.getKeyPageAbove(i.key),k=i.dropPosition;if(w==null&&(w=E.getFirstKey?.(),k="before"),w==null)break;i={type:"item",key:w,dropPosition:k}}let{draggingKeys:s}=B,u=V(n);r.state.getDropOperation({target:i,types:T,allowedOperations:m.allowedDropOperations,isInternal:u,draggingKeys:s})==="cancel"&&(i=p(i,T,m.allowedDropOperations,d,!1)??p(i,T,m.allowedDropOperations,l,!1))}r.state.setTarget(i??r.state.target);break}}r.props.onKeyDown?.(b)}})},[r,n,v,g]);let $=at();return Ae.set(t,{id:$,ref:n}),{collectionProps:ke(y,{id:$,"aria-describedby":null})}}function Ct(e,t,n){let{dropProps:r}=kt(),a=Ar(t);x.useEffect(()=>{if(n.current)return Gr({element:n.current,target:e.target,getDropOperation(g,$){let{draggingKeys:l}=B,d=V(a);return t.getDropOperation({target:e.target,types:g,allowedOperations:$,isInternal:d,draggingKeys:l})},activateButtonRef:e.activateButtonRef})},[n,e.target,t,a,e.activateButtonRef]);let o=Me(),{draggingKeys:y}=B,c=V(a),D=o&&t.getDropOperation({target:e.target,types:z(o.dragTarget.items),allowedOperations:o.dragTarget.allowedDropOperations,isInternal:c,draggingKeys:y})!=="cancel",v=t.isDropTarget(e.target);return x.useEffect(()=>{o&&v&&n.current&&n.current.focus()},[v,o,n]),{dropProps:{...r,"aria-hidden":!o||D?void 0:"true"},isDropTarget:v}}function ln(e){return e&&e.__esModule?e.default:e}function sn(e,t,n){let{target:r}=e,{collection:a}=t,o=re(ln(ne),"@react-aria/dnd"),y=Me(),{dropProps:c}=Ct(e,t,n),D=at(),v=p=>p==null?"":a.getTextValue?.(p)??a.getItem(p)?.textValue??"",g="",$;if(r.type==="root")g=o.format("dropOnRoot"),$=`${D} ${Ir(t)}`;else if(r.dropPosition==="on")g=o.format("dropOnItem",{itemText:v(r.key)});else{let p,b;if(r.dropPosition==="before"){let m=a.getItem(r.key)?.prevKey,E=m!=null?a.getItem(m):null;p=E?.type==="item"?E.key:null}else p=r.key;if(r.dropPosition==="after"){let m=a.getItem(r.key)?.nextKey,E=m!=null?a.getItem(m):null;b=E?.type==="item"?E.key:null}else b=r.key;p!=null&&b!=null?g=o.format("insertBetween",{beforeItemText:v(p),afterItemText:v(b)}):p!=null?g=o.format("insertAfter",{itemText:v(p)}):b!=null&&(g=o.format("insertBefore",{itemText:v(b)}))}let l=t.isDropTarget(r),d=y?c["aria-hidden"]:"true";return{dropIndicatorProps:{...c,id:D,"aria-roledescription":o.format("dropIndicator"),"aria-label":g,"aria-labelledby":$,"aria-hidden":d,tabIndex:-1},isDropTarget:l,isHidden:!l&&!!d}}function un(e){return e&&e.__esModule?e.default:e}const We={keyboard:{start:"dragDescriptionKeyboard",end:"endDragKeyboard"},touch:{start:"dragDescriptionTouch",end:"endDragTouch"},virtual:{start:"dragDescriptionVirtual",end:"endDragVirtual"}};function dn(e){let{hasDragButton:t,isDisabled:n}=e,r=re(un(ne),"@react-aria/dnd"),a=x.useRef({options:e,x:0,y:0}).current;a.options=e;let o=x.useRef(null),[y,c]=x.useState(!1),D=u=>{o.current=u,c(!!u)},{addGlobalListener:v,removeAllGlobalListeners:g}=nr(),$=x.useRef(null),l=u=>{if(u.defaultPrevented)return;if(u.stopPropagation(),$.current==="virtual"){u.preventDefault(),m(M(u)),$.current=null;return}typeof e.onDragStart=="function"&&e.onDragStart({type:"dragstart",x:u.clientX,y:u.clientY});let h=e.getItems();u.dataTransfer.clearData?.(),Ce(u.dataTransfer,h);let w=P.all;if(typeof e.getAllowedDropOperations=="function"){let F=e.getAllowedDropOperations();w=P.none;for(let I of F)w|=P[I]||P.none}be(w);let k=gt[w]||"none";u.dataTransfer.effectAllowed=k==="cancel"?"none":k,typeof e.preview?.current=="function"&&e.preview.current(h,(F,I,H)=>{if(!F)return;let N=F.getBoundingClientRect(),U=u.currentTarget.getBoundingClientRect(),J=u.clientX-U.x,Z=u.clientY-U.y;(J>N.width||Z>N.height)&&(J=N.width/2,Z=N.height/2);let X=J,K=Z;typeof I=="number"&&typeof H=="number"&&(X=I,K=H),X=Math.max(0,Math.min(X,N.width)),K=Math.max(0,Math.min(K,N.height));let A=2*Math.round(N.height/2);F.style.height=`${A}px`,u.dataTransfer.setDragImage(F,X,K)}),v(window,"drop",F=>{F.preventDefault(),F.stopPropagation(),console.warn("Drags initiated from the React Aria useDrag hook may only be dropped on a target created with useDrop. This ensures that a keyboard and screen reader accessible alternative is available.")},{once:!0}),a.x=u.clientX,a.y=u.clientY;let C=M(u);requestAnimationFrame(()=>{D(C)})},d=u=>{u.stopPropagation(),!(u.clientX===a.x&&u.clientY===a.y)&&(typeof e.onDragMove=="function"&&e.onDragMove({type:"dragmove",x:u.clientX,y:u.clientY}),a.x=u.clientX,a.y=u.clientY)},p=u=>{if(u.stopPropagation(),typeof e.onDragEnd=="function"){let h={type:"dragend",x:u.clientX,y:u.clientY,dropOperation:ee[u.dataTransfer.dropEffect]};ce&&(h.dropOperation=ee[ce]),e.onDragEnd(h)}D(null),g(),be(P.none),ye(void 0)};x.useEffect(()=>()=>{if(o.current&&(!o.current.isConnected||parseInt(x.version,10)<17)){if(typeof a.options.onDragEnd=="function"){let u={type:"dragend",x:0,y:0,dropOperation:ee[ce||"none"]};a.options.onDragEnd(u)}D(null),be(P.none),ye(void 0)}},[a]);let b=u=>{u.pointerType!=="keyboard"&&u.pointerType!=="virtual"||m(u.target)},m=u=>{if(typeof a.options.onDragStart=="function"){let h=u.getBoundingClientRect();a.options.onDragStart({type:"dragstart",x:h.x+h.width/2,y:h.y+h.height/2})}Hr({element:u,items:a.options.getItems(),allowedDropOperations:typeof a.options.getAllowedDropOperations=="function"?a.options.getAllowedDropOperations():["move","copy","link"],onDragEnd(h){D(null),typeof a.options.onDragEnd=="function"&&a.options.onDragEnd(h)}},r),D(u)},E=Oe(),T=y?We[E].end:We[E].start,i=Be(r.format(T)),s={};return t||(s={...i,onPointerDown(u){if($.current=et(u.nativeEvent)?"virtual":u.pointerType,u.width<1&&u.height<1&&nt()&&rt())$.current="virtual";else{let h=u.currentTarget.getBoundingClientRect(),w=u.clientX-h.x,k=u.clientY-h.y,C=h.width/2,F=h.height/2;Math.abs(w-C)<=.5&&Math.abs(k-F)<=.5?$.current="virtual":$.current=u.pointerType}},onKeyDownCapture(u){M(u)===u.currentTarget&&u.key==="Enter"&&(u.preventDefault(),u.stopPropagation())},onKeyUpCapture(u){M(u)===u.currentTarget&&u.key==="Enter"&&(u.preventDefault(),u.stopPropagation(),m(M(u)))},onClick(u){(Qe(u.nativeEvent)||$.current==="virtual")&&(u.preventDefault(),u.stopPropagation(),m(M(u)))}}),n?{dragProps:{draggable:"false"},dragButtonProps:{},isDragging:!1}:{dragProps:{...s,draggable:"true",onDragStart:l,onDrag:d,onDragEnd:p},dragButtonProps:{...i,onPress:b},isDragging:y}}function cn(e){return e&&e.__esModule?e.default:e}const pn={keyboard:{selected:"dragSelectedKeyboard",notSelected:"dragDescriptionKeyboard"},touch:{selected:"dragSelectedLongPress",notSelected:"dragDescriptionLongPress"},virtual:{selected:"dragDescriptionVirtual",notSelected:"dragDescriptionVirtual"}};function fn(e,t){let n=re(cn(ne),"@react-aria/dnd"),r=t.isDisabled||t.selectionManager.isDisabled(e.key),{dragProps:a,dragButtonProps:o}=dn({getItems(){return t.getItems(e.key)},preview:t.preview,getAllowedDropOperations:t.getAllowedDropOperations,hasDragButton:e.hasDragButton,onDragStart(d){t.startDrag(e.key,d),Lr(t.draggingKeys)},onDragMove(d){t.moveDrag(d)},onDragEnd(d){let{dropOperation:p}=d,b=p==="cancel"?!1:V();t.endDrag({...d,keys:t.draggingKeys,isInternal:b}),vt()}}),y=t.collection.getItem(e.key),c=t.getKeysForDrag(e.key).size,D=c>1&&t.selectionManager.isSelected(e.key),v,g,$=Oe();if(!e.hasDragButton&&t.selectionManager.selectionMode!=="none"){let d=pn[$][D?"selected":"notSelected"];e.hasAction&&$==="keyboard"&&(d+="Alt"),D?g=n.format(d,{count:c}):g=n.format(d),delete a.onClick}else if(D)v=n.format("dragSelectedItems",{count:c});else{let d=t.collection.getTextValue?.(e.key)??y?.textValue??"";v=n.format("dragItem",{itemText:d})}let l=Be(g);if(g&&Object.assign(a,l),!e.hasDragButton&&e.hasAction){let{onKeyDownCapture:d,onKeyUpCapture:p}=a;$==="touch"&&delete a["aria-describedby"],a.onKeyDownCapture=b=>{b.altKey&&d?.(b)},a.onKeyUpCapture=b=>{b.altKey&&p?.(b)}}return{dragProps:r?{}:a,dragButtonProps:{...o,isDisabled:r,"aria-label":v}}}function gn(e,t,n){let{draggingCollectionRef:r}=B;t.draggingKeys.size>0&&r?.current!==n.current&&Rr(n)}const yn=_.forwardRef(function(t,n){let r=t.children,[a,o]=x.useState(null),y=x.useRef(null),c=x.useRef(void 0);return x.useImperativeHandle(n,()=>(D,v)=>{let g=r(D),$,l,d;g&&typeof g=="object"&&"element"in g?($=g.element,l=g.x,d=g.y):$=g,Ft.flushSync(()=>{o($)}),v(y.current,l,d),c.current=requestAnimationFrame(()=>{o(null)})},[r]),x.useEffect(()=>()=>{c.current&&cancelAnimationFrame(c.current)},[]),a?_.createElement("div",{style:{zIndex:-100,position:"fixed",top:0,left:-1e5},ref:y},a):null});function mn(e){let{getItems:t,isDisabled:n,collection:r,selectionManager:a,onDragStart:o,onDragMove:y,onDragEnd:c,preview:D,getAllowedDropOperations:v}=e,[,g]=x.useState(!1),$=x.useRef(new Set),l=x.useRef(null),d=p=>{let b=new Set;if(a.isSelected(p))for(let m of a.selectedKeys){let E=r.getItem(m);if(E){let T=!1,i=E.parentKey;for(;i!=null;){if(a.selectedKeys.has(i)){T=!0;break}let s=r.getItem(i);i=s?s.parentKey:null}T||b.add(m)}}else b.add(p);return b};return{collection:r,selectionManager:a,get draggedKey(){return l.current},get draggingKeys(){return $.current},isDragging(p){return $.current.has(p)},getKeysForDrag:d,getItems(p){let b=d(p),m=[];for(let E of b){let T=r.getItem(E)?.value;T!=null&&m.push(T)}return t(d(p),m)},isDisabled:n,preview:D,getAllowedDropOperations:v,startDrag(p,b){let m=d(p);$.current=m,l.current=p,a.setFocused(!1),g(!0),typeof o=="function"&&o({...b,keys:m})},moveDrag(p){typeof y=="function"&&y({...p,keys:$.current})},endDrag(p){let{isInternal:b}=p;typeof c=="function"&&c({...p,keys:$.current,isInternal:b}),$.current=new Set,l.current=null,g(!1)}}}function hn(e){let{acceptedDragTypes:t="all",isDisabled:n,onInsert:r,onRootDrop:a,onItemDrop:o,onReorder:y,onMove:c,shouldAcceptItemDrop:D,collection:v,selectionManager:g,onDropEnter:$,getDropOperation:l,onDrop:d}=e,[p,b]=x.useState(null),m=x.useRef(null),E=i=>{if(i.dropPosition==="before"){let s=v.getItem(i.key);return s&&s.prevKey!=null?{type:"item",key:s.prevKey,dropPosition:"after"}:null}else if(i.dropPosition==="after"){let s=v.getItem(i.key);return s&&s.nextKey!=null?{type:"item",key:s.nextKey,dropPosition:"before"}:null}return null},T=x.useCallback(i=>{let{target:s,types:u,allowedOperations:h,isInternal:w,draggingKeys:k}=i;if(n||!s)return"cancel";if(t==="all"||t.some(C=>u.has(C))){let C=r&&s.type==="item"&&!w&&(s.dropPosition==="before"||s.dropPosition==="after"),F=y&&s.type==="item"&&w&&(s.dropPosition==="before"||s.dropPosition==="after")&&Dn(v,s,k),I=s.type!=="item"||s.dropPosition!=="on"||!D||D(s,u),H=c&&s.type==="item"&&w&&I,N=a&&s.type==="root"&&!w,U=o&&s.type==="item"&&s.dropPosition==="on"&&!(w&&s.key!=null&&k.has(s.key))&&I;if(d||C||F||H||N||U)return l?l(s,u,h):h[0]}return"cancel"},[n,v,t,l,r,a,o,D,y,c,d]);return{collection:v,selectionManager:g,isDisabled:n,target:p,setTarget(i){if(this.isDropTarget(i))return;let s=m.current;s&&typeof e.onDropExit=="function"&&e.onDropExit({type:"dropexit",x:0,y:0,target:s}),i&&typeof $=="function"&&$({type:"dropenter",x:0,y:0,target:i}),m.current=i??null,b(i??null)},isDropTarget(i){let s=m.current;return!s||!i?!1:we(i,s)?!0:i?.type==="item"&&s?.type==="item"&&i.key!==s.key&&i.dropPosition!==s.dropPosition&&i.dropPosition!=="on"&&s.dropPosition!=="on"?we(E(i),s)||we(i,E(s)):!1},getDropOperation(i){let{target:s,isInternal:u,draggingKeys:h}=i;if(u&&s.type==="item"&&h.size>0){if(h.has(s.key)&&s.dropPosition==="on")return"cancel";let w=s.key;for(;w!=null;){let C=v.getItem(w)?.parentKey;if(C!=null&&h.has(C))return"cancel";w=C??null}}return T(i)}}}function we(e,t){if(!e)return!t;switch(e.type){case"root":return t?.type==="root";case"item":return t?.type==="item"&&t?.key===e.key&&t?.dropPosition===e.dropPosition}}function Dn(e,t,n){let r=e.getItem(t.key);for(let a of n)if(e.getItem(a)?.parentKey!==r?.parentKey)return!1;return!0}class bn{constructor(t,n,r){this.collection=t,this.ref=n,this.layout=r?.layout||"stack",this.orientation=r?.orientation||"vertical",this.direction=r?.direction||"ltr"}getPrimaryStart(t){return this.orientation==="horizontal"?t.left:t.top}getPrimaryEnd(t){return this.orientation==="horizontal"?t.right:t.bottom}getSecondaryStart(t){return this.orientation==="horizontal"?t.top:t.left}getSecondaryEnd(t){return this.orientation==="horizontal"?t.bottom:t.right}getFlowStart(t){return this.layout==="stack"?this.getPrimaryStart(t):this.getSecondaryStart(t)}getFlowEnd(t){return this.layout==="stack"?this.getPrimaryEnd(t):this.getSecondaryEnd(t)}getFlowSize(t){return this.getFlowEnd(t)-this.getFlowStart(t)}getDropTargetFromPoint(t,n,r){if(this.collection[Symbol.iterator]().next().done||!this.ref.current)return{type:"root"};let a=this.ref.current.getBoundingClientRect(),o=this.orientation==="horizontal"?t:n,y=this.orientation==="horizontal"?n:t;o+=this.getPrimaryStart(a),y+=this.getSecondaryStart(a);let c=this.layout==="stack"?o:y,D=this.orientation==="horizontal"&&this.direction==="rtl",v=this.layout==="grid"&&this.orientation==="vertical"&&this.direction==="rtl",g=this.layout==="stack"?D:v,$=this.ref.current?.dataset.collection,l=this.ref.current.querySelectorAll($?`[data-collection="${CSS.escape($)}"]`:"[data-key]"),d=new Map;for(let i of l)i instanceof HTMLElement&&i.dataset.key!=null&&d.set(i.dataset.key,i);let p=[...this.collection].filter(i=>i.type==="item");if(p.length<1)return{type:"root"};let b=0,m=p.length;for(;b{k?b=i+1:m=i};if(othis.getPrimaryEnd(h))w(!D);else if(ythis.getSecondaryEnd(h))w(!v);else{let k={type:"item",key:s.key,dropPosition:"on"};if(r(k))c<=this.getFlowStart(h)+5&&r({...k,dropPosition:"before"})?k.dropPosition=g?"after":"before":c>=this.getFlowEnd(h)-5&&r({...k,dropPosition:"after"})&&(k.dropPosition=g?"before":"after");else{let C=this.getFlowStart(h)+this.getFlowSize(h)/2;c<=C&&r({...k,dropPosition:"before"})?k.dropPosition=g?"after":"before":c>=C&&r({...k,dropPosition:"after"})&&(k.dropPosition=g?"before":"after")}return k}}let E=p[Math.min(b,p.length-1)];return a=d.get(String(E.key))?.getBoundingClientRect(),a&&(o{let{onDrop:n,onInsert:r,onItemDrop:a,onReorder:o,onMove:y,onRootDrop:c,getItems:D,renderDragPreview:v,renderDropIndicator:g,dropTargetDelegate:$}=e,l=!!D,d=!!(n||r||a||o||y||c),p={};return l&&(p.useDraggableCollectionState=function(m){return mn({...m,...e})},p.useDraggableCollection=gn,p.useDraggableItem=fn,p.DragPreview=yn,p.renderDragPreview=v,p.isVirtualDragging=zr),d&&(p.useDroppableCollectionState=function(m){return hn({...m,...e})},p.useDroppableItem=Ct,p.useDroppableCollection=function(m,E,T){return on({...m,...e},E,T)},p.useDropIndicator=sn,p.renderDropIndicator=g,p.dropTargetDelegate=$,p.ListDropTargetDelegate=bn),p},[e])}}function ue({children:e,tone:t,action:n}){return f.jsxs("span",{className:Ie("rp-tag",t),children:[f.jsx("span",{className:"rp-tag-label",children:e}),n]})}function Je({label:e,children:t}){return f.jsx("div",{className:"rp-tags",role:"group","aria-label":e,children:t})}function vn({label:e,message:t,children:n}){return f.jsxs("div",{className:"rp-actionbar",role:"region","aria-label":e,children:[f.jsx("span",{"aria-live":"polite",children:t}),f.jsx("div",{className:"rp-toolbar",children:n})]})}function En({className:e,...t}){return f.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:12,height:12,viewBox:"0 0 12 12","aria-hidden":"true",focusable:"false",className:Ie("rp-icon",e),...t,children:[1.6,6,10.4].flatMap(n=>[3.8,8.2].map(r=>f.jsx("circle",{cx:r,cy:n,r:1.1,fill:"currentColor"},`${r}-${n}`)))})}function xn(e,t){return e.flatMap(n=>{if(n.kind!=="subscription")return[];const r=t.filter(o=>o.provider_id===n.id),a=new Set(r.map(o=>o.subscription_tag).filter(Boolean));return a.size!==1?[]:[{tag:[...a][0],label:n.name,count:r.length}]})}const Ze=6;function wn(e,t,n,r,a){const o=new Map(Ke(e).map(l=>[l.name,Le(l)])),y=ot(e,t),c=Ke(y),D=new Map(n.map(l=>[l.tag,l])),v=a("arrange.lastMember"),g=c.map(l=>{const d=Le(l),p=o.get(l.name),b=Ve(l.filters),m=d.rules.length?Ve(d.rules):null,E=t.filter(s=>s.group===l.name),T=new Set(E.flatMap(s=>s.kind==="removeNode"?r.filter(u=>u.name===s.value):s.kind==="removeSubscription"?r.filter(u=>u.subscription_tag===s.value):[])),i=m?r.filter(m).map(s=>s.name):[];return{name:l.name,isNew:!p,holdsAll:l.filters.length===0,names:d.names.map(s=>({name:s,isNew:!!p&&!p.names.includes(s),blocked:Ge(l,"name",s)?v:null})),subscriptions:d.subtags.map(s=>({tag:s,label:D.get(s)?.label??s,count:D.get(s)?.count??null,isNew:!!p&&!p.subtags.includes(s),blocked:Ge(l,"subtag",s)?v:null})),rules:d.rules,ruleNote:d.rules.length?a("arrange.ruleNote",{n:d.rules.length}):null,ruleNodes:i.slice(0,Ze),ruleMore:Math.max(0,i.length-Ze),stillIn:[...T].filter(b).map(s=>s.name),removedNames:E.flatMap(s=>s.kind==="removeNode"?[s.value]:[]),removedSubscriptions:E.flatMap(s=>s.kind==="removeSubscription"?[{tag:s.value,label:D.get(s.value)?.label??s.value}]:[])}}),$=new Set(r.map(l=>l.name));return{groups:g,stagedText:y,unknown:new Set(g.flatMap(l=>l.names.filter(d=>!$.has(d.name)).map(d=>d.name))),emptyNew:g.filter(l=>l.isNew&&l.holdsAll).map(l=>l.name)}}function St(e,t){return e?t.kind==="node"?e.names.some(n=>n.name===t.value):e.subscriptions.some(n=>n.tag===t.value):!1}function Tn(e){try{const t=JSON.parse(e);if(!t||typeof t!="object")return null;const{kind:n,value:r}=t;return(n==="node"||n==="subscription")&&typeof r=="string"&&r?{kind:n,value:r}:null}catch{return null}}function kn(e,t,n){const r=a=>t.find(o=>o.tag===a)?.label??a;switch(e.kind){case"addNode":return n("arrange.change.addNode",{name:e.value,group:e.group});case"removeNode":return n("arrange.change.removeNode",{name:e.value,group:e.group});case"addSubscription":return n("arrange.change.addSubscription",{name:r(e.value),group:e.group});case"removeSubscription":return n("arrange.change.removeSubscription",{name:r(e.value),group:e.group});case"createGroup":return n("arrange.change.createGroup",{group:e.group})}}function Te(e,t){const n={addNode:"removeNode",removeNode:"addNode",addSubscription:"removeSubscription",removeSubscription:"addSubscription"};if(t.kind==="createGroup")return e.some(a=>a.kind==="createGroup"&&a.group===t.group)?e:[...e,t];if((t.kind==="addNode"||t.kind==="addSubscription")&&!it(t.value))return e;const r=e.findIndex(a=>a.kind===n[t.kind]&&a.group===t.group&&"value"in a&&a.value===t.value);return r!==-1?e.filter((a,o)=>o!==r):e.some(a=>a.kind===t.kind&&a.group===t.group&&"value"in a&&a.value===t.value)?e:[...e,t]}function Kn(e,t){const n=e[t];return e.filter((r,a)=>a!==t&&!(n.kind==="createGroup"&&r.group===n.group))}const pe="application/x-doona-placeable";function Cn(e){const t=W(),n=ar(),r=n.data?.resources,a=or(He(r,"nodes",{whileLoading:!1})),o=ir(He(r,"providers",{whileLoading:!1})),y=a.data,[c,D]=x.useState([]),v=lr(c.length>0,()=>D([])),g=e.main?.content??"",$=x.useMemo(()=>xn(o.data?.providers??[],y??[]),[o.data,y]),l=x.useMemo(()=>wn(g,c,$,y??[],t),[g,c,$,y,t]),d=x.useMemo(()=>new Map(l.groups.map(K=>[K.name,K])),[l.groups]),{contains:p}=Pr({sensitivity:"base"}),[b,m]=x.useState(""),E=x.useDeferredValue(b).trim(),T=x.useMemo(()=>(y??[]).filter(K=>!E||p(K.name,E)||p(K.protocol??"",E)),[y,E,p]),i=x.useMemo(()=>$.filter(K=>!E||p(K.label,E)),[$,E,p]),[s,u]=x.useState(!1),[h,w]=x.useState(!1),[k,C]=x.useState(null),F=e.writable?e.main?null:"arrange.noMain":"arrange.readOnly",I=K=>{h||(C(null),D(K))},H=(K,A)=>{A.some(O=>!it(O.value))&&ze("negative",t("config.unquotable")),I(O=>A.filter(he=>!St(d.get(K),he)).reduce((he,je)=>Te(he,{kind:je.kind==="node"?"addNode":"addSubscription",group:K,value:je.value}),O))},N=(K,A)=>I(O=>Te(O,{kind:A.kind==="node"?"removeNode":"removeSubscription",group:K,value:A.value})),U=new Set(l.groups.map(K=>K.name)),J=K=>Cr(K,U,t),Z=async()=>{w(!0),C(null);try{const K=await e.apply(A=>ot(A,c));K.kind==="invalid"&&C(t("ui.writeInvalid",{n:K.errors})),K.kind==="failed"&&C(t("arrange.failed",{error:ur(K.error,t)})),K.kind==="ok"&&(ze("positive",t("arrange.applied",{n:c.length})),D([]),v.clear(),u(!1))}finally{w(!1)}},X=x.useMemo(()=>{if(!c.length)return[];const K=l.stagedText.split(`
-`),A=new Set(c.map(O=>O.group));return Ke(l.stagedText).filter(O=>A.has(O.name)).map(O=>({group:O.name,text:K.slice(O.from,O.to+1).join(`
-`)}))},[l.stagedText,c]);return{groups:l.groups,unknown:l.unknown,byGroup:d,subscriptions:i,nodes:T,search:b,setSearch:m,loading:n.loading&&!n.data||a.loading&&!y||o.loading&&!o.data,error:[n,a,o].find(K=>K.error&&!K.data)?.error??(e.main?null:e.error),retry:x.useCallback(()=>void sr(),[]),blocked:F?t(F):null,busy:e.busy||h,applying:h,failure:k,changes:c,changeLines:c.map(K=>kn(K,$,t)),pendingText:t("arrange.pending",{n:c.length}),place:H,unplace:N,drop:K=>I(A=>Kn(A,K)),discard:()=>I(()=>[]),nameProblem:J,create:(K,A)=>I(O=>Te(O,{kind:"createGroup",group:K,policy:A})),reviewing:s&&c.length>0,setReviewing:K=>{h||u(K)},preview:X,canApply:c.length>0&&l.emptyNew.length===0&&!F&&!h,applyNote:l.emptyNew.length?t("arrange.emptyNew",{group:l.emptyNew[0]}):null,apply:Z}}function Hn({source:e,groups:t}){const n=W(),r=Cn(e),a=x.useMemo(()=>new Map((t??[]).map(o=>[o.name,o])),[t]);return r.error?f.jsx(dr,{error:r.error,onRetry:r.retry}):r.loading?f.jsx(cr,{}):f.jsxs("div",{className:"rp-arrange",children:[f.jsxs("div",{className:"rp-row",children:[f.jsxs("p",{className:"rp-note rp-grow",children:[f.jsx("span",{className:"rp-wide-only",children:n("arrange.note")}),f.jsx("span",{className:"rp-narrow-only",children:n("arrange.selectHint")})]}),f.jsx(Pn,{m:r})]}),r.blocked&&f.jsx(Q,{tone:"informative",children:r.blocked}),f.jsxs("div",{className:"rp-arrange-grid",children:[f.jsx("div",{className:"rp-col",children:r.groups.length?r.groups.map(o=>f.jsx(Sn,{group:o,live:a.get(o.name),m:r},o.name)):f.jsx(lt,{children:n("policy.empty")})}),f.jsx(Fn,{m:r})]}),r.changes.length>0&&f.jsxs(vn,{label:n("arrange.pendingRegion"),message:r.pendingText,children:[f.jsx(L,{quiet:!0,onPress:r.discard,isDisabled:r.busy,children:n("arrange.discard")}),f.jsx(L,{accent:!0,onPress:()=>r.setReviewing(!0),children:n("arrange.review")})]}),f.jsx(Bn,{m:r})]})}function Sn({group:e,live:t,m:n}){const r=W(),a=dt(),o=x.useId(),y=!!n.blocked,c=t?Sr(t.policy,r):null,D=async $=>{const l=await Promise.all($.filter(jr).filter(d=>d.types.has(pe)).map(d=>d.getText(pe)));n.place(e.name,l.flatMap(d=>Tn(d)??[]))},v=($,l,d)=>f.jsx(L,{quiet:!0,icon:!0,small:!0,label:r("arrange.remove",{name:$,group:e.name}),tip:d??void 0,isDisabled:y||n.applying||!!d,onPress:()=>n.unplace(e.name,l),children:f.jsx(ct,{})}),g=($,l)=>f.jsx(L,{quiet:!0,small:!0,label:r("arrange.undoRemove",{name:$}),isDisabled:n.applying,onPress:()=>n.place(e.name,[l]),children:r("arrange.undoShort")});return f.jsx(rn,{className:yr("rp-drop"),"aria-label":r("arrange.dropInto",{group:e.name}),isDisabled:y||n.applying,getDropOperation:$=>$.has(pe)?"copy":"cancel",onDrop:$=>void D($.items),children:({isDropTarget:$})=>f.jsxs(f.Fragment,{children:[f.jsx("div",{className:"rp-row",children:f.jsxs("span",{className:"rp-cluster",children:[f.jsx("h3",{className:"rp-h3",id:o,children:e.name}),c&&f.jsx(Xe,{tip:c.id,children:c.label}),t&&f.jsx(pr,{small:!0,tone:"neutral",children:r("arrange.memberCount",{n:t.member_count})}),e.isNew&&f.jsx(Xe,{children:r("arrange.new")})]})}),e.holdsAll&&f.jsx("p",{className:"rp-note",children:r("arrange.holdsAll")}),(e.names.length>0||e.removedNames.length>0)&&f.jsxs(Je,{label:r("arrange.byName"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:r("arrange.byName")}),e.names.map(l=>f.jsx(ue,{tone:l.isNew?"new":void 0,action:v(l.name,{kind:"node",value:l.name},l.blocked),children:l.name},l.name)),e.removedNames.map(l=>f.jsx(ue,{tone:"removed",action:g(l,{kind:"node",value:l}),children:l},l))]}),(e.subscriptions.length>0||e.removedSubscriptions.length>0)&&f.jsxs(Je,{label:r("arrange.bySubscription"),children:[f.jsx("span",{className:"rp-label rp-tags-title",children:r("arrange.bySubscription")}),e.subscriptions.map(l=>f.jsx(ue,{tone:l.isNew?"new":void 0,action:v(l.label,{kind:"subscription",value:l.tag},l.blocked),children:l.count===null?l.label:r("arrange.subscriptionCount",{name:l.label,n:l.count})},l.tag)),e.removedSubscriptions.map(l=>f.jsx(ue,{tone:"removed",action:g(l.label,{kind:"subscription",value:l.tag}),children:l.label},l.tag))]}),e.rules.length>0&&f.jsxs("div",{className:"rp-arrange-rules",children:[f.jsx("span",{className:"rp-label",children:r("arrange.byRule")}),e.rules.map(l=>f.jsx(pt,{as:"code",text:l},l)),e.ruleNodes.length>0&&f.jsx("span",{children:e.ruleMore?r("arrange.ruleSelectsMore",{names:de(a,e.ruleNodes),n:e.ruleMore}):r("arrange.ruleSelects",{names:de(a,e.ruleNodes)})}),f.jsxs("span",{className:"rp-label",children:[e.ruleNote," ",f.jsx(fr,{appearance:"link",href:gr("config",{tab:"source"}),children:r("arrange.editSource")})]})]}),e.stillIn.length>0&&f.jsx(Q,{tone:"informative",children:r("arrange.stillIn",{names:de(a,e.stillIn)})}),$&&f.jsx("div",{className:"rp-drop-hint","aria-hidden":"true",children:r("arrange.dropHint")})]})})}function Fn({m:e}){const t=W(),n=x.useId(),r=!!e.blocked||e.applying,[a,o]=x.useState("all"),[y,c]=x.useState(new Set),D=x.useMemo(()=>[...a==="node"?[]:e.subscriptions.map(d=>({id:"subscription:"+d.tag,item:{kind:"subscription",value:d.tag},label:d.label,meta:t("arrange.subscriptionMeta",{n:d.count})})),...a==="subscription"?[]:e.nodes.map(d=>({id:"node:"+d.name,item:{kind:"node",value:d.name},label:d.name,meta:d.protocol??""}))],[a,e.subscriptions,e.nodes,t]),v=x.useMemo(()=>new Map(D.map(d=>[d.id,d])),[D]),g=y==="all"?D:[...y].flatMap(d=>v.get(String(d))??[]),{dragAndDropHooks:$}=$n({getItems:d=>[...d].flatMap(p=>v.has(String(p))?[{[pe]:JSON.stringify(v.get(String(p)).item),"text/plain":v.get(String(p)).label}]:[]),getAllowedDropOperations:()=>["copy"],isDisabled:r}),l=e.groups.filter(d=>g.some(p=>!St(d,p.item)));return f.jsxs(mr,{title:t("arrange.tray"),titleId:n,className:"rp-tray",children:[f.jsx(ut,{search:!0,label:t("arrange.search"),value:e.search,onChange:e.setSearch}),f.jsx(hr,{label:t("arrange.show"),value:a,onChange:d=>o(d),items:[["all",t("ui.all")],["subscription",t("arrange.subscriptions")],["node",t("arrange.nodes")]]}),f.jsx(kr,{layout:Kr,layoutOptions:{rowHeight:48},children:f.jsx(wr,{"aria-labelledby":n,className:"rp-tray-list",items:D,selectionMode:"multiple",selectionBehavior:"toggle",selectedKeys:y,onSelectionChange:c,dragAndDropHooks:$,renderEmptyState:()=>f.jsx(lt,{children:t("arrange.trayEmpty")}),children:d=>f.jsxs(Tr,{id:d.id,textValue:d.label,className:"rp-item rp-tray-row",children:[f.jsx(Dr,{slot:"drag",className:Ie(br({quiet:!0,icon:!0,small:!0}),"rp-drag"),"aria-label":t("arrange.drag",{name:d.label}),children:f.jsx(En,{})}),f.jsx($r,{}),f.jsxs("span",{className:"rp-grow",children:[f.jsx(vr,{children:d.label}),f.jsx("span",{className:"desc",children:d.meta})]})]})})}),f.jsxs("div",{className:"rp-tray-bar",children:[f.jsx("span",{className:"rp-grow rp-label","aria-live":"polite",children:g.length?t("arrange.selected",{n:g.length}):t("arrange.selectHint")}),g.length>0&&f.jsx(L,{quiet:!0,small:!0,onPress:()=>c(new Set),children:t("arrange.clear")}),f.jsx(Er,{label:t("arrange.addSelected"),isDisabled:r||!l.length,items:l.map(d=>({id:d.name,label:d.name})),onAction:d=>{e.place(d,g.map(p=>p.item)),c(new Set)},children:t("arrange.addSelected")})]})]})}function Pn({m:e}){const t=W(),n=x.useId(),[r,a]=x.useState(!1),[o,y]=x.useState(""),[c,D]=x.useState(Ue[0].id),[v,g]=x.useState(!1),$=e.nameProblem(o.trim()),l=()=>{y(""),D(Ue[0].id),g(!1)};return f.jsxs(f.Fragment,{children:[f.jsx(L,{small:!0,onPress:()=>a(!0),isDisabled:!!e.blocked||e.applying,children:t("arrange.newGroup")}),f.jsx(st,{title:t("arrange.newGroup"),narrow:!0,isOpen:r,onOpenChange:d=>{a(d),d||l()},footer:d=>f.jsxs(f.Fragment,{children:[f.jsx(L,{onPress:d,children:t("ui.cancel")}),f.jsx(L,{accent:!0,type:"submit",form:n,children:t("arrange.create")})]}),children:f.jsxs("form",{id:n,className:"rp-form",onSubmit:d=>{d.preventDefault(),g(!0),!$&&(e.create(o.trim(),c),a(!1),l())},children:[f.jsx(ut,{label:t("arrange.groupName"),value:o,onChange:y,description:t("arrange.groupNameHint"),error:v&&$?$:void 0,spellCheck:!1}),f.jsx(Fr,{value:c,onChange:D}),f.jsx("p",{className:"rp-label",children:t("arrange.newGroupNote")})]})})]})}function Bn({m:e}){const t=W(),n=dt();return f.jsxs(st,{title:t("arrange.reviewTitle"),isOpen:e.reviewing,onOpenChange:e.setReviewing,footer:r=>f.jsxs(f.Fragment,{children:[f.jsx(L,{onPress:r,isDisabled:e.applying,children:t("ui.cancel")}),f.jsx(L,{accent:!0,isPending:e.applying,isDisabled:!e.canApply,onPress:()=>void e.apply(),children:t("arrange.apply")})]}),children:[e.failure&&f.jsx(Q,{takeFocus:!0,children:e.failure}),e.applyNote&&f.jsx(Q,{children:e.applyNote}),e.unknown.size>0&&f.jsx(Q,{tone:"informative",children:t("arrange.unknown",{names:de(n,[...e.unknown])})}),f.jsx("ol",{className:"rp-arrange-changes",children:e.changeLines.map((r,a)=>f.jsxs("li",{className:"rp-row",children:[f.jsx("span",{className:"rp-grow",children:r}),f.jsx(L,{quiet:!0,icon:!0,small:!0,label:t("arrange.undo",{change:r}),isDisabled:e.applying,onPress:()=>e.drop(a),children:f.jsx(ct,{})})]},a))}),f.jsx(xr,{title:t("arrange.showText"),children:e.preview.map(r=>f.jsx(pt,{as:"pre",className:"rp-arrange-preview",text:r.text},r.group))}),f.jsx("p",{className:"rp-label",children:t("arrange.applyNote")})]})}export{Hn as Arrange};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Config-BTdL4dU5.js b/luci-app-honk/root/etc/honk/dashboard/assets/Config-BTdL4dU5.js
new file mode 100644
index 000000000..7bb013d84
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Config-BTdL4dU5.js
@@ -0,0 +1,4 @@
+import{r as m,j as o}from"./vendor-react-Bf71BWbF.js";import{a0 as Re,aq as Te,ap as Xe,db as Ye,cL as q,an as Ze,a1 as xe,dc as en,dd as Le,de as nn,$ as Fe,y as Oe,h as we,N as oe,M as tn,df as sn,cP as Ae,u as F,a2 as ee,a as ne,a5 as on,ab as rn,a7 as ye,dg as ce,ay as He,dh as _e,bf as an,be as ln,A as cn,di as dn,bb as H,cO as $e,X as re,bc as Y,cA as de,dj as Be,dk as un,F as fn,dl as pn,D as gn,I as le,B as z,aG as ue,bx as Z,aH as fe,L as mn,aC as $,dm as hn,dn as bn,dp as vn,dq as xn,cz as wn,dr as yn,G as jn,ds as kn,b as Ie,ac as Sn,b2 as pe,T as G,af as Cn,bz as Nn,b1 as Dn,aE as We,dt as Mn,ae as Pn,du as En,aF as zn,E as Rn,j as Tn,aD as Ln,bn as Fn}from"./index-CXHBmSa5.js";import{d as On}from"./files-BxEOxSF8.js";import{r as An,d as Hn,a as _n,t as je,b as $n,w as ke,v as Bn,c as In,n as Wn}from"./setup-B5f1cfyO.js";import{g as Vn}from"./policyText-CAFy3qpo.js";import{a as Kn,s as Gn,c as Un}from"./nav-BeFLfZq8.js";import{S as qn,a as Jn,E as _,C as te,b as ge,l as Qn,h as Xn,c as Se,r as Yn,d as Zn,e as et,f as nt,i as tt,g as st,s as ot,k as rt,t as at,j as it,m as lt,n as ct,o as dt,p as ut,q as ft,u as pt,v as gt,w as Ve,D as J,R as mt,x as ht,y as bt,z as vt,A as xt,B as wt,F as Ke,H as yt,G as K}from"./vendor-editor-CF5uj9id.js";import{d as jt,s as kt,D as Ge}from"./DaeCode-STEiRZuV.js";import{A as St}from"./AddCircle-Db3HxlxQ.js";import{D as Ct}from"./Table-D0NFHHNQ.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";const Nt=["global","subscription","node","group","dns","routing"],Dt=(t,s,e)=>t?e("config.moduleEditBlocked"):s?e("ui.changeApplying"):void 0;function Ce(t,s){return`${q(t)}:${s.line+1}-${s.endLine+1}`}function Mt(t,s,e){return t.slice(0,s.from)+e+t.slice(s.to)}function Pt(t,s){const{section:e,text:n}=t,a=s.find(f=>f.id===e.id);if(a?.source?.content_sha256===e.source.content_sha256)return{next:null,conflict:!1};if(!a?.source?.content||!a.block)return{next:null,conflict:!0};const r=a.source.content.slice(a.block.from,a.block.to),l=e.source.content.slice(e.block.from,e.block.to);return{next:{section:{...a,source:a.source,block:a.block},text:n===l?r:n},conflict:r!==l&&n!==l&&r!==n}}function Et(t,s,e,n){const a=e.line+n.split(`
+`).length;return t.filter(r=>r.source_id===s&&r.line!==null&&r.line>e.line&&r.line<=a).map(r=>({line:r.line-e.line,column:r.column,level:r.level,message:r.message}))}function zt(t,s){return t.filter(e=>e.source_id===s&&e.line!==null).map(e=>({line:e.line,column:e.column,level:e.level,message:e.message}))}function ae(t,s,e){return e.filter(n=>n.from>s.open&&n.to<=s.close&&n.depth===s.depth+1&&n.parens===0&&n.kind==="text"&&t.slice(n.from,n.to)==="->").length}function Ne(t,s,e){const n=s.filter(a=>a.from>t.open&&a.to<=t.close&&a.depth===t.depth+1&&a.parens===0&&(a.kind==="quoted"||a.kind==="text")&&!e.some(r=>a.from>=r.from&&a.to<=r.to));return e.length+n.length}function Rt(t,s,e,n,a,r){const l=oe(s,e,n);switch(t){case"global":return r("config.moduleSettings",{n:l.length});case"subscription":return r("config.moduleSubscriptions",{n:Ne(e,n,l)});case"node":return r("config.moduleNodes",{n:Ne(e,n,l)});case"group":return r("config.moduleGroups",{n:e.children.length,policies:Fe(a,e.children.map(c=>{const f=oe(s,c,n).find(u=>u.name==="policy")?.value;if(!f)return c.name;const i=tn(f);return r("ui.valuePair",{label:c.name,value:i?Vn({kind:i,native:f},r).label:f})}))});case"dns":{const c=e.children.filter(i=>i.name==="upstream"),f=e.children.filter(i=>i.name==="routing").flatMap(i=>i.children);return[r("config.moduleDnsUpstreams",{n:c.reduce((i,u)=>i+oe(s,u,n).length,0)}),r("config.moduleDnsRequests",{n:f.filter(i=>i.name==="request").reduce((i,u)=>i+ae(s,u,n),0)}),r("config.moduleDnsResponses",{n:f.filter(i=>i.name==="response").reduce((i,u)=>i+ae(s,u,n),0)})].join(r("ui.listSeparator"))}case"routing":{const c=r("config.moduleRules",{n:ae(s,e,n)}),f=l.find(i=>i.name==="fallback")?.value;return f?c+r("ui.separator")+r("ui.valuePair",{label:"fallback",value:f}):c}}}function Tt(t,s,e,n){const r=t.filter(i=>i.kind==="main"||i.kind==="include").map(i=>({source:i,...Oe(i.content??"")})),l=t.find(i=>i.kind==="main")??null,c=Nt.flatMap(i=>{const u=i==="group"?we("policies"):i==="node"||i==="subscription"?we("nodes"):null,g=r.flatMap(({source:d,blocks:v,tokens:S})=>v.filter(w=>w.name===i).map((w,b)=>({id:`${d.id}:${i}:${b}`,kind:i,source:d,block:w,href:u,range:Ce(d,w),summary:Rt(i,d.content,w,S,e,n),note:null})));return g.length||l&&l.content===void 0?g:[{id:i,kind:i,source:l,block:null,href:u,range:l?q(l):"config.dae",summary:l?.content===void 0?"":l.writable?n("config.moduleAbsent",{file:q(l)}):n("config.moduleAbsentReadOnly"),note:l?.content===void 0?n("config.contentWithheld"):null}]}),f=r.flatMap(({source:i,blocks:u})=>i.content===void 0?[{id:i.id,kind:q(i),source:i,block:null,href:null,range:q(i),summary:"",note:n("config.contentWithheld")}]:s.redactedSections(u).map(({block:g,name:d},v)=>({id:`${i.id}:${g.name}:${v}`,kind:d,source:i,block:null,href:null,range:Ce(i,g),summary:"",note:n("config.incomplete")})));return[...c,...f]}function Q(t,s,e){const n=Re(Kn,t.kind,e);return{id:t.id,label:Ye(t)?`${n} ${t.id.slice(0,8)}`:t.path,kind:n,facts:e("config.sourceFacts",{n:t.line_count,size:Xe(String(t.bytes),s)}),loaded:e("config.loadedAt",{time:Te(t.loaded_at,s)}),hasContent:t.content!==void 0}}const Lt={generated:{label:"config.kind.generated",note:"config.generatedNote"},subscription:{label:"config.kind.subscription",note:"config.subscriptionNote"},disabled:{label:"config.readOnly",note:"config.readOnlyNote",help:"config.readOnlyHelp"},secret:{label:"config.secretSource",note:"config.secretNote"},refused:{label:"config.readOnly",note:"config.refusedNote"},withheld:{label:"config.withheldSource",note:"config.contentWithheld"},redacted:{label:"config.redactedSource",note:"config.redactedNote"}};function Ft(t,s,e,n,a){const r=t.kind==="generated"||t.kind==="subscription"?t.kind:s?t.writable?t.content===void 0?"withheld":e===!1?"redacted":null:n.holdsCredentials(t)?"secret":"refused":"disabled";if(!r)return null;const l=Lt[r],c=a(l.label);return{reason:r,label:c,note:a(l.note),...l.help&&{help:{title:c,text:a(l.help)}}}}const Ot={error:"err",warning:"warn",info:"info"},At={error:"config.level.error",warning:"config.level.warning",info:"config.level.info"};function se(t,s,e,n){const a=new Map(s.map(l=>[l.id,q(l)])),r=new Map;for(const l of t){const c=JSON.stringify([l.level,l.source_id,l.line,l.column,l.code,l.message]),f=r.get(c);f?f.count++:r.set(c,{item:l,count:1})}return[...r].map(([l,{item:c,count:f}])=>{const i=a.get(c.source_id)??c.source_id,u=Ze(c.code,c.message,n).summary,g=f>1?n("config.repeated",{text:u,n:xe(f,e)}):u,d=en(c.code)?n("config.backendDetail",{text:g,message:c.message}):g;return{id:l,level:c.level,tone:Ot[c.level],levelText:Re(At,c.level,n),sourceId:c.source_id,line:c.line,where:c.line===null?i:`${i}:${c.line}`,message:g,code:c.code,detail:c.line===null?d:n("config.atFile",{file:i,line:xe(c.line,e),message:d}),count:f}})}function ie(t){return{...An(t),rules:t.trim()?"keep":Hn}}function Ht(t,s,e){return s.content_sha256===e.content_sha256?null:t?"conflict":"follow"}function _t(t,s,e){return{groupUsedText:t.rules==="keep"?null:je[t.rules].groups.length?e("config.wizardNamedGroups",{names:Fe(s,je[t.rules].groups.map(n=>n.name))}):e("config.wizardGroupUsed",{name:t.group??$n}),rows:t.subscriptions.flatMap((n,a)=>n.raw!==void 0&&!n.raw.trim()?[]:[{index:a,name:n.name,url:n.url,raw:n.raw!==void 0&&!n.name?n.raw.trim():null,nameError:n.raw===void 0&&!nn(n.name.trim())?e("config.unquotable"):void 0,error:n.url!==""&&!_n(n.url)?e("config.wizardSubscriptionHelp"):n.raw===void 0&&!Le(n.url.trim())?e("config.unquotable"):void 0,description:a===0?e("config.wizardSubscriptionHelp"):void 0,removeLabel:e("config.wizardRemove",{name:n.name||n.raw?.trim()||""})}])}}function $t(t,s,e,n,a){if(!s&&e)return{disabled:!0,tip:e};const r=a(t==="validate"?"config.saveValidating":n?"config.saveShortcutMac":"config.saveShortcut");return{disabled:!!t||!s,tip:r}}function me({busy:t,complete:s=!0,conflict:e,invalid:n=null,changed:a},r){return t||s===null?null:s?e?r("config.saveConflict"):n??(a?null:r("config.noChanges")):r("config.incomplete")}function Ue(t,s,e,n){if(t)return null;const a=s.filter(l=>l.kind==="main"||l.kind==="include");if(a.some(l=>e(l)===void 0))return null;const r=a.find(l=>l.kind==="main");return n(r?.content!==void 0&&e(r)?"config.validateOther":"config.validateNoMain")}function Bt(t,s,e){return[{label:e("config.generation"),value:t,help:{title:e("config.generation"),text:e("config.generationHelp")}},[e("config.revision"),s]]}function he(t,s,e){const n=e?.id,a=e?.content;return m.useMemo(()=>{const r=t.filter(l=>l.kind==="main"||l.kind==="include");return r.some(l=>s(l)===void 0)?null:sn(r.filter(l=>s(l)),n!==void 0&&a!==void 0?{id:n,content:a}:void 0)},[t,s,n,a])}const It=600,Wt=()=>{};function qe(t,s){const{validate:e,cancel:n}=Ae(Wt);m.useEffect(()=>{if(!t)return;let a=!0;const r=setTimeout(()=>{e({sources:t,mode:"full"}).then(l=>{a&&l&&s(l.diagnostics)})},It);return()=>{a=!1,clearTimeout(r),n()}},[t,e,n,s])}function Vt(t){const s=F(),e=Ae(t),n=m.useMemo(()=>e.error instanceof cn&&e.error.status===422?e.error.details?.diagnostics??[]:null,[e.error]);return m.useEffect(()=>{if(e.error)if(n){const a=dn(n);H("negative",a?s("config.writeRestart",{n:a}):s("ui.writeInvalid",{n:n.filter(r=>r.level==="error").length}))}else $e(e.error,s,s("ui.writeFailed"))},[e.error,n,s]),{...e,diagnostics:n}}function Kt({go:t,query:s}){const e=F(),n=ee[ne()],a=on().data?.resources,r=rn(ye(a,"config",{whileLoading:!0})),l=Vt(r.refetch),c=m.useMemo(()=>new URLSearchParams(s),[s]),f=m.useMemo(()=>r.data?.sources??[],[r.data]),i=f.find(M=>M.kind==="main")??null,u=f.find(M=>M.id===c.get("source"))??f[0]??null,g=u?.id??null,d=M=>t("config",re(s,{source:M,line:null})),v=(M,T)=>t("config",re(s,{tab:"source",source:M,line:T===null?null:String(T)})),S=Number(c.get("line"))||null,w=m.useMemo(()=>(r.data?.diagnostics??[]).filter(M=>M.source_id===g),[r.data,g]),b=m.useMemo(()=>{const M=r.data?.diagnostics??[];return{error:M.filter(T=>T.level==="error").length,warning:M.filter(T=>T.level==="warning").length}},[r.data]),x=Gn(a,i),k=Un(x),C=ye(a,"config_validate",{whileLoading:!1})&&(a?.config_validate.modes??[]).includes("full"),D=a?.config.writable===!0,h=ce(f),y=He().data,N=m.useMemo(()=>_e(y),[y]),E=u?Ft(u,D,h(u),N,e):null,R=!!u&&!E,j=c.has("source")||i?.content===void 0?"source":!i.content.trim()&&x?"setup":"modules",L=an(s,k.map(M=>M.id),j),A=u?{source:u,sources:f,open:v,diagnostics:w,canValidate:C&&R,canWrite:R,readOnly:E,isComplete:h,contentOffered:a?.config.content===!0,editor:l,focusLine:S}:null,I=x&&i?{main:i,editor:l,onDone:()=>t("config",re(s,{tab:"source",source:i.id}))}:null,W=a?.config.create===!0&&a.config.writable===!0?{sources:f,contentOffered:a.config.content===!0,refetch:r.refetch,open:M=>v(M,null)}:null,V=r.data?{config:r.data,editor:l,canValidate:C,open:v}:null;return{error:r.error,reload:r.refetch,loading:r.loading&&!r.data,ready:!!r.data,metadata:r.data?Bt(r.data.generation_id,r.data.revision,e):[],redacted:!!r.data?.secrets_redacted,tabs:k.map(M=>({id:M.id,label:e(M.titleKey)})),tab:L,setTab:M=>t("config",ln(s,M,null)),selectedId:g??"",select:d,sourceProps:A,newSourceProps:W,wizardProps:I,modulesProps:r.data?{config:r.data,editor:l,canWrite:D,canValidate:C,open:v}:null,validateProps:V,sourceModel:u?{...Q(u,n,e),readOnly:E}:null,sourceOptions:f.map(M=>{const T=Q(M,n,e);return{id:T.id,label:T.label,desc:T.kind}}),exportSource:()=>{u?.content!==void 0&&On(q(u),u.content,"text/plain;charset=utf-8")},summaryTone:b.error?"err":b.warning?"warn":"ok",summaryText:b.error?e("config.errors",{n:b.error}):b.warning?e("config.warnings",{n:b.warning}):e("config.clean")}}function Gt({source:t,sources:s,diagnostics:e,canValidate:n,canWrite:a,readOnly:r,isComplete:l,editor:c,focusLine:f}){const i=F(),u=ee[ne()],[g,d]=m.useState(null),[v,S]=m.useState(null),w=a&&l(t)===!0,b=m.useRef(!1),k=(c.errorSource===t.id?c.diagnostics:null)??v??e,C=m.useMemo(()=>zt(k,t.id),[k,t.id]),D=g?.text??t.content??"",h=()=>Be(s,{id:t.id,content:D}),[y,N]=m.useState(null);Y(f,()=>N(null));const E=g!==null&&g.text!==t.content,R=E&&g.origin.content_sha256!==t.content_sha256,j=de(E,()=>{d(null),S(null)});m.useEffect(()=>c.cancel,[c.cancel,j.revision]);const L=g?.text,A=he(s,l,{id:t.id,content:D});qe(n&&L!==void 0?A:null,S);const I=(p,O=!0)=>{S(p.diagnostics);const U=p.diagnostics.find(X=>X.source_id===t.id&&X.level==="error"&&X.line!==null);return N(U?U.line:null),p.valid?O&&H("positive",i("config.valid")):H("negative",i("config.invalid",{n:p.diagnostics.filter(X=>X.level==="error").length})),p.valid},W=async()=>{if(!A)return!1;const p=await c.validate({sources:A,mode:"full"});return p?I(p):!1},V=async()=>{if(g===null||c.busy||!w||R)return;const p=await c.apply(g.origin,g.text);if(S(null),!!p){if(p.diagnostics){I({valid:!1,diagnostics:p.diagnostics},!1);return}H("positive",i("config.saved",{path:Q(t,u,i).label})),j.clear(),d(null)}},M=()=>{d(null),S(null)},T=p=>{p===t.content?M():d(O=>({text:p,origin:O?.origin??t}))},P=r?()=>{b.current||(b.current=!0,H("info",i("config.readOnlyAttempt"),{detail:r.note}))}:void 0,B=Q(t,u,i);return{writable:w,note:r?.note??i(n?"config.editNoteValidate":"config.editNote"),refused:P,shown:se(k,s,u,i),marks:C,text:D,outbounds:h,focus:y??f,dirty:E,conflict:R?i("config.changedOnDisk"):null,keep:()=>d(p=>p&&{...p,origin:t}),validate:W,save:V,cancel:M,change:T,view:B,busy:!!c.busy,validating:c.busy==="validate",saving:c.busy==="save",saveButton:R?{disabled:!0,tip:i("config.changedOnDisk")}:$t(c.busy,w,r?.note??null,un,i),validateDisabled:!!c.busy||!A,reason:E?!w&&r?r.note:me({busy:!!c.busy,conflict:!!R,changed:!0},i):n&&!c.busy?Ue(A,s,l,i):null}}function Ut({config:t,editor:s}){const e=F(),n=ee[ne()],[a,r]=m.useState("all"),[l,c]=m.useState(null),[f,i]=m.useState(null);Y(t.generation_id,()=>{c(null),i(null)});const u=m.useMemo(()=>se(l?.diagnostics??t.diagnostics,t.sources,n,e),[l,t.diagnostics,t.sources,n,e]),g=k=>u.reduce((C,D)=>C+(D.level===k?D.count:0),0),d=g("error"),v=g("warning"),S=a==="all"?u:u.filter(k=>k.level===a),w=ce(t.sources),b=he(t.sources,w);return{level:a,setLevel:r,selected:f,setSelected:i,shown:S,validate:()=>{b&&s.validate({sources:b,mode:"full"}).then(k=>{k&&(c(k),i(null))})},summaryTone:d?"err":v?"warn":"ok",summary:d?e("config.failed",{errors:e("config.errors",{n:d}),warnings:e("config.warnings",{n:v})}):v?e("config.passedWarnings",{n:v}):e("config.passed"),lastRun:l?e("config.lastRun",{time:Te(l.validated_at,n)}):e("config.acceptedDiagnostics",{generation:t.generation_id}),validating:s.busy==="validate",blocked:!!s.busy||!b,reason:s.busy?null:Ue(b,t.sources,w,e),levels:[["all",e("config.levelAll",{n:d+v+g("info")})],["error",e("config.levelErrors",{n:d})],["warning",e("config.levelWarnings",{n:v})],["info",e("config.levelInfo",{n:g("info")})]]}}const qt=qn.define({name:"dae",languageData:{commentTokens:{line:"#"},closeBrackets:{brackets:["(","{","'",'"']}},startState:kt,token:jt}),Jt=["global","subscription","node","group","dns","routing"].map(t=>({label:t,type:"keyword"})),Qt=gn.map(t=>({label:t,type:"property",apply:t+": "})),Xt=["domain","dip","sip","dport","sport","l4proto","ipversion","pname","mac","dscp","qname","qtype","upstream"].map(t=>({label:t,type:"function",apply:t+"("})),Yt=["geosite","geoip","suffix","full","keyword","regex"].map(t=>({label:t,type:"constant",apply:t+":"})),De=pn.map(t=>({label:t,type:"constant"})),Zt=fn.map(t=>({label:t,type:"keyword"})),es=[{label:"fallback",type:"keyword",apply:"fallback: "},{label:"include",type:"keyword",apply:"include "}];function ns(t,s){const e=t.matchBefore(/[\w.-]*/);if(!e)return null;const n=t.state.doc.lineAt(t.pos),a=n.text.slice(0,t.pos-n.from),r=/->\s*[\w.-]*$/.test(a)||/^\s*fallback:\s*[\w.-]*$/.test(a);if(e.from===e.to&&!t.explicit&&!r)return null;const l=t.state.doc.sliceString(0,t.pos),{blocks:c,tokens:f}=Oe(l),i=f.at(-1);if(i?.to===t.pos&&(i.kind==="quoted"||i.kind==="comment"))return null;const u=c.find(d=>d.close===t.pos)?.name;let g;if(r)g=[...s().map(d=>({label:d.name,apply:d.written,type:"variable"})),...Zt];else if(/\b(domain|dip|sip|qname)\(\s*[\w.-]*$/.test(a))g=Yt;else if(u===void 0)g=Jt.map(d=>({...d,apply:(v,S,w,b)=>{const x=d.label+` {
+
+}`;v.dispatch({changes:{from:w,to:b,insert:x},selection:{anchor:w+d.label.length+4}})}}));else if(u==="routing"||u==="dns")g=[...Xt,...es];else if(u==="global")g=Qt;else if(u==="group")g=/\bpolicy\s*:\s*[\w.-]*$/.test(a)?De:[...De.map(d=>({...d,apply:"policy: "+d.label})),{label:"filter",type:"property",apply:"filter: "}];else return null;return{from:e.from,options:g,validFor:/^[\w.-]*$/}}function ts(t){return Jn({override:[s=>ns(s,t)]})}function ss(t,s){return s.filter(e=>e.line>=1&&e.line<=t.doc.lines).map(e=>{const n=t.doc.line(e.line),a=Math.max(0,(e.column??1)-1),r=new TextEncoder().encode(n.text);let l=0;for(let f=0;fa)break;f+=i,l+=i===4?2:1}return{from:n.from+l,to:n.to,severity:e.level,message:e.message}})}function os(t){return t.key==="Backspace"||t.key==="Delete"||t.key==="Enter"?!0:[...t.key].length===1&&!t.ctrlKey&&!t.metaKey}function rs(t){let s=!1;const e=n=>(n.state.readOnly&&t(),!1);return _.domEventHandlers({keydown:(n,a)=>os(n)&&e(a),paste:(n,a)=>e(a),cut:(n,a)=>e(a),pointerdown:n=>(s=n.pointerType==="touch",!1),click:(n,a)=>s&&e(a)})}const as=[["Completions","cm.completions"],["Find","cm.find"],["Replace","cm.replace"],["next","cm.next"],["previous","cm.previous"],["all","cm.all"],["match case","cm.matchCase"],["regexp","cm.regexp"],["by word","cm.byWord"],["replace","cm.replaceOne"],["replace all","cm.replaceAll"],["close","close"],["Go to line","cm.gotoLine"],["go","cm.go"],["current match","cm.currentMatch"],["replaced $ matches","cm.replacedMatches"],["replaced match on line $","cm.replacedOnLine"],["on line","cm.onLine"],["Selection deleted","cm.selectionDeleted"],["Control character","cm.controlCharacter"]],Me=t=>ge.phrases.of(Object.fromEntries(as.map(([s,e])=>[s,t(e)]))),is=_.theme({"&":{backgroundColor:"var(--rp-base)",color:"var(--rp-text)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",fontSize:"var(--rp-text-sm)"},"&.cm-focused":{outline:"none",borderColor:"var(--rp-accent)",boxShadow:"0 0 0 1px var(--rp-accent)"},".cm-scroller":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace",lineHeight:"20px",maxHeight:"70vh",fontVariantLigatures:"none",borderRadius:"calc(var(--rp-r-md) - 1px)"},".cm-content":{padding:"8px 0",caretColor:"var(--rp-text)"},".cm-line":{padding:"0 12px"},".cm-gutters":{backgroundColor:"var(--rp-base)",color:"var(--rp-muted)",border:"none"},".cm-lineNumbers .cm-gutterElement":{padding:"0 8px 0 12px",minWidth:"40px"},".cm-activeLine, .cm-focusLine":{backgroundColor:"color-mix(in srgb, var(--rp-hl-med) 60%, transparent)"},".cm-activeLineGutter":{backgroundColor:"transparent",color:"var(--rp-text)"},".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection":{backgroundColor:"var(--rp-hl-high)"},".cm-cursor":{borderLeftColor:"var(--rp-text)"},".cm-matchingBracket":{backgroundColor:"color-mix(in srgb, var(--rp-accent) 20%, transparent)",outline:"none"},".cm-selectionMatch":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 25%, transparent)"},".cm-tooltip.cm-tooltip-lint":{backgroundColor:"var(--rp-text)",color:"var(--rp-on-text)",border:"none",borderRadius:"var(--rp-r-sm)",padding:"2px 0"},".cm-tooltip-lint .cm-diagnostic":{border:"none",padding:"2px 8px",fontSize:"var(--rp-text-xs)",lineHeight:"16px",fontFamily:"inherit"},".cm-tooltip-lint .cm-diagnosticText":{color:"inherit"},".cm-diag-line-error":{backgroundColor:"color-mix(in srgb, var(--rp-negative) 14%, transparent)"},".cm-diag-line-warning":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 16%, transparent)"},".cm-diag-line-info":{backgroundColor:"color-mix(in srgb, var(--rp-foam) 14%, transparent)"},".cm-lintRange-error":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-negative)",textUnderlineOffset:"3px"},".cm-lintRange-warning":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-notice)",textUnderlineOffset:"3px"},".cm-lintRange-info":{backgroundImage:"none",textDecoration:"underline dotted var(--rp-foam)",textUnderlineOffset:"3px"},".cm-tooltip":{backgroundColor:"var(--rp-surface)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]":{backgroundColor:"var(--rp-selected)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace"},".cm-panels":{backgroundColor:"var(--rp-surface)",color:"var(--rp-text)"},".cm-panels-bottom":{borderTop:"1px solid var(--rp-hl-med)"},".cm-textfield":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundColor:"var(--rp-base)",color:"var(--rp-text)"},".cm-button":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundImage:"none",backgroundColor:"var(--rp-overlay)",color:"var(--rp-text)"}}),ls=yt.define([{tag:K.comment,color:"var(--rp-code-comment)"},{tag:K.keyword,color:"var(--rp-code-keyword)",fontWeight:"700"},{tag:K.string,color:"var(--rp-code-string)"},{tag:K.number,color:"var(--rp-code-number)"},{tag:K.propertyName,color:"var(--rp-code-propertyName)"},{tag:K.variableName,color:"var(--rp-code-variableName)"},{tag:K.operator,color:"var(--rp-code-operator)"},{tag:K.punctuation,color:"var(--rp-code-punctuation)"}]),cs=ht.of((t,s)=>{const e=t.lineAt(s,-1),n=e.from>0?t.lineAt(e.from-1,-1):null;if(!n)return 0;const a=/^\s*/.exec(n.text)[0].length,r=/\{\s*(#.*)?$/.test(n.text),l=/^\s*\}/.test(e.text);return Math.max(0,a+(r?2:0)-(l?2:0))}),Je=Ke.define(),ds={error:J.line({class:"cm-diag-line cm-diag-line-error"}),warning:J.line({class:"cm-diag-line cm-diag-line-warning"}),info:J.line({class:"cm-diag-line cm-diag-line-info"})},us=Ve.define({create:()=>J.none,update(t,s){let e=t.map(s.changes);for(const n of s.effects){if(!n.is(Je))continue;const a=new mt,r={error:0,warning:1,info:2},l=new Map;for(const c of n.value){if(c.line<1||c.line>s.state.doc.lines)continue;const f=l.get(c.line);(!f||r[c.level]f-i)){const f=s.state.doc.line(c).from;a.add(f,f,ds[l.get(c).level])}e=a.finish()}return e},provide:t=>_.decorations.from(t)}),fs=[],Pe=wt.define(),Qe=Ke.define(),ps=J.line({class:"cm-focusLine"}),gs=Ve.define({create:()=>J.none,update(t,s){let e=t.map(s.changes);for(const n of s.effects)n.is(Qe)&&(e=J.set(ps.range(s.state.doc.line(n.value).from)));return e},provide:t=>_.decorations.from(t)}),Ee=t=>[ge.readOnly.of(t),_.editable.of(!t),t?gs:[bt(),vt(),xt()]];function be({value:t,onChange:s,readOnly:e=!1,marks:n=fs,focusLine:a,label:r,outbounds:l,onSave:c,onReadOnlyAttempt:f,compact:i}){const u=m.useRef(null),g=m.useRef(null),d=m.useRef(s),v=m.useRef(l),S=m.useRef(c),w=m.useRef(f);m.useEffect(()=>{d.current=s,v.current=l,S.current=c,w.current=f});const b=m.useRef(new te),x=F(),k=m.useRef(new te),C=m.useRef(new te),D=m.useRef(new te);return m.useLayoutEffect(()=>{const h=new _({parent:u.current,state:ge.create({doc:t,extensions:[Qn(),Xn(),D.current.of(Se()),Yn(),us,Zn(),et(),nt(),tt.of(" "),st(),cs,ts(()=>v.current?.()??[]),qt,ot(ls),is,rt.of([{key:"Mod-s",run:()=>(S.current?.(),!0)},{key:"Mod-/",run:at},{key:"Mod-g",run:it},...lt,...ct,...dt,...ut,...ft,pt]),b.current.of(Ee(e)),k.current.of(Me(x)),C.current.of(_.contentAttributes.of({"aria-label":r,tabindex:"0"})),rs(()=>w.current?.()),_.updateListener.of(y=>{y.docChanged&&!y.transactions.some(N=>N.annotation(Pe))&&d.current?.(y.state.doc.toString())})]})});return g.current=h,()=>{h.destroy(),g.current=null}},[]),m.useEffect(()=>{const h=g.current;h&&h.dispatch({effects:b.current.reconfigure(Ee(e))})},[e]),m.useEffect(()=>{g.current?.dispatch({effects:k.current.reconfigure(Me(x))})},[x]),m.useEffect(()=>{g.current?.dispatch({effects:C.current.reconfigure(_.contentAttributes.of({"aria-label":r,tabindex:"0"}))})},[r]),m.useEffect(()=>{const h=g.current;!h||h.state.doc.toString()===t||(h.dispatch({changes:{from:0,to:h.state.doc.length,insert:t},annotations:Pe.of(!0),effects:D.current.reconfigure([])}),h.dispatch({effects:D.current.reconfigure(Se())}))},[t]),m.useEffect(()=>{const h=g.current;if(!h)return;const y=gt(h.state,ss(h.state,n)),N=Array.isArray(y.effects)?y.effects:y.effects?[y.effects]:[];h.dispatch({...y,effects:[...N,Je.of(n)]})},[n]),m.useEffect(()=>{const h=g.current;if(!h||!a||a<1||a>h.state.doc.lines)return;const y=h.state.doc.line(a);h.dispatch({selection:{anchor:y.from},effects:[Qe.of(a),_.scrollIntoView(y.from,{y:"center"})]}),h.focus()},[a]),o.jsx("div",{className:i?"rp-editor compact":"rp-editor",ref:u})}function ve({message:t,busy:s,keep:e,discard:n}){const a=F();return o.jsx(le,{action:(e||n)&&o.jsxs("span",{className:"rp-toolbar",children:[e&&o.jsx(z,{isDisabled:s,onPress:e,children:a("config.keepChanges")}),n&&o.jsx(z,{isDisabled:s,onPress:n,children:a("config.discard")})]}),children:t})}function ms({config:t,editor:s,canWrite:e,canValidate:n,open:a}){const r=F(),l=ne(),c=ee[l],f=He().data,i=m.useMemo(()=>_e(f),[f]),u=m.useMemo(()=>Tt(t.sources,i,l,r),[t,i,l,r]),g=ce(t.sources),[d,v]=m.useState(null),[S,w]=m.useState(null),b=d!==null&&d.text!==d.section.source.content.slice(d.section.block.from,d.section.block.to),x=m.useMemo(()=>d?Pt(d,u):null,[d,u]),k=!!x?.conflict;Y(x&&!x.conflict?x.next:null,p=>{p&&v(p)});const C=de(b,()=>{v(null),w(null)}),{clear:D}=C;m.useEffect(()=>s.cancel,[s.cancel,C.revision]);const h=m.useMemo(()=>d?Mt(d.section.source.content,d.section.block,d.text):null,[d]),y=d?.section.source.id,N=he(t.sources,g,y&&h!==null?{id:y,content:h}:void 0);qe(n&&h!==null?N:null,w);const E=(s.errorSource===y?s.diagnostics:null)??S??t.diagnostics,R=m.useMemo(()=>E.filter(p=>p.source_id===y),[E,y]),j=d?.section.id,L=m.useMemo(()=>({own:R,sectionId:j}),[R,j]),[A,I]=m.useState([]);Y(L,p=>I(d?Et(p.own,d.section.source.id,d.section.block,d.text):[]));const W=m.useMemo(()=>Be(t.sources,y&&h!==null?{id:y,content:h}:void 0),[y,h,t]),V=()=>{s.cancel(),D(),v(null),w(null)},M=(p,O)=>{w(O),H(p?"positive":"negative",p?r("config.valid"):r("config.invalid",{n:O.filter(U=>U.level==="error").length}))},T=async()=>{if(!d||!N||h===null||s.busy)return;const p=await s.validate({sources:N,mode:"full"});p&&M(p.valid,p.diagnostics)},P=async()=>{if(!d||h===null||s.busy||!b||k)return;const p=await s.apply(d.section.source,h);if(p){if(p.diagnostics){M(!1,p.diagnostics);return}H("positive",r("config.saved",{path:Q(d.section.source,c,r).label})),D(),v(null),w(null)}};return{cards:(d&&!u.some(p=>p.id===d.section.id)?[...u,d.section]:u).map(p=>{const O=d?.section.id===p.id,U=e&&!!p.source?.writable&&!!p.block&&g(p.source)===!0;return{...p,editing:O,canEdit:U,editDisabled:b||!!s.busy,editTip:Dt(b,!!s.busy,r),editReason:U&&!O&&b?r("config.moduleEditBlocked"):null,note:p.note??(p.source&&p.block&&g(p.source)===!1?r("config.incomplete"):null),muted:!p.block,manual:p.source&&p.source.content!==void 0?()=>a(p.source.id,p.block?p.block.line+1:null):null,edit:()=>{b||s.busy||!e||!p.source?.writable||!p.block||g(p.source)!==!0||(w(null),v({section:{...p,source:p.source,block:p.block},text:p.source.content.slice(p.block.from,p.block.to)}))}}}),text:d?.text??"",change:p=>v(O=>O?{...O,text:p}:null),marks:A,diagnostics:se(R,t.sources,c,r),outbounds:()=>W,dirty:b,saveReason:me({busy:!!s.busy,conflict:!!k,changed:b},r),conflict:k?r("config.changedOnDisk"):null,keep:k&&x?.next?()=>v(x.next):null,busy:!!s.busy,saving:s.busy==="save",validating:s.busy==="validate",canValidate:n&&!!N,validate:T,save:P,cancel:V}}function hs(t){const s=F(),e=ms(t);return o.jsx("div",{className:"rp-page",children:e.cards.map(n=>o.jsxs(ue,{"aria-label":n.kind,children:[o.jsx(Z,{reason:n.editReason,children:o.jsxs("div",{className:"rp-row",children:[o.jsxs("span",{className:"rp-cluster",children:[o.jsx("h3",{className:"rp-h3 rp-code",children:n.kind}),o.jsx("span",{className:"rp-label rp-code",children:n.range}),n.editing&&e.dirty&&o.jsx(fe,{tone:"warn",children:s("config.unsaved")})]}),o.jsxs("span",{className:"rp-cluster",children:[n.href&&o.jsx(mn,{appearance:"button",href:n.href,children:s("config.moduleOpen")}),n.canEdit&&!n.editing&&o.jsx(z,{isDisabled:n.editDisabled,tip:n.editTip,onPress:n.edit,children:s("config.edit")}),n.manual&&!n.editing&&o.jsx(z,{quiet:!0,tip:s("config.moduleManualTip"),onPress:n.manual,children:s("config.moduleManual")})]})]})}),o.jsx($,{small:!0,tone:n.muted?"muted":"info",children:n.summary}),n.note&&o.jsx($,{small:!0,tone:"muted",children:n.note}),n.editing&&o.jsxs(o.Fragment,{children:[o.jsx(be,{label:n.range,value:e.text,onChange:e.change,readOnly:e.busy,marks:e.marks,outbounds:e.outbounds,onSave:e.dirty&&!e.busy?()=>void e.save():void 0}),e.conflict&&o.jsx(ve,{message:e.conflict,busy:e.busy,keep:e.keep}),e.diagnostics.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":s("config.diagnostics"),children:e.diagnostics.map(a=>o.jsx("div",{role:"listitem",children:o.jsx($,{small:!0,tone:a.tone,children:a.detail})},a.id))}),o.jsx(Z,{reason:e.saveReason,children:o.jsxs("div",{className:"rp-cluster",children:[e.canValidate&&o.jsx(z,{isPending:e.validating,isDisabled:e.busy,onPress:()=>void e.validate(),children:s("config.validate")}),o.jsx(z,{accent:!0,isPending:e.saving,isDisabled:e.busy||!e.dirty||!!e.conflict,onPress:()=>void e.save(),children:s("config.save")}),o.jsx(z,{isDisabled:e.busy,onPress:e.cancel,children:s("ui.cancel")})]})})]})]},n.id))})}function bs({sources:t,contentOffered:s,refetch:e,open:n}){const a=F(),r=t.find(h=>h.kind==="main"),l=m.useMemo(()=>s&&r?.content!==void 0?hn(r.content):null,[s,r]),c=m.useMemo(()=>bn(l??[]),[l]),f=m.useMemo(()=>vn(t),[t]),[i,u]=m.useState(null),[g,d]=m.useState(null),{busy:v,create:S}=xn(e),w=wn(),b=i?.text??"",x=c.find(h=>h.pattern===i?.pattern)??null,k=x?x.prefix+b+x.suffix:b,C=b?x?yn(b,x):jn(b):null,D=async h=>{if(!b||C||v)return;const y=w.start();try{const N=await S(k);if(!N||(H("positive",a("config.newSourceCreated",{path:k})),!y()))return;h(),N.id&&n(N.id)}catch(N){y()?d(E=>({id:(E?.id??0)+1,text:Ie(N,a)})):$e(N,a,a("config.newSourceFailed",{path:k}))}};return{isOpen:i!==null,show:()=>{w.next(),d(null),u({text:c.length?"":kn(l??[]),pattern:c[0]?.pattern??""})},hide:()=>{w.next(),u(null)},choices:c,choice:x,setChoice:h=>u(y=>y&&{...y,pattern:h}),text:b,setText:h=>u(y=>y&&{...y,text:h}),error:C?a(C):void 0,unmatched:!!b&&!C&&f!==null&&!f(k),problem:g,busy:v,canSubmit:!!b&&!C&&!v,submit:D}}function vs(t){const s=F(),e=bs(t);return o.jsxs(o.Fragment,{children:[o.jsxs(z,{onPress:e.show,children:[o.jsx(St,{}),s("config.newSource")]}),o.jsxs(Sn,{title:s("config.newSourceTitle"),narrow:!0,isOpen:e.isOpen,onOpenChange:n=>{n||e.hide()},footer:n=>o.jsxs(o.Fragment,{children:[o.jsx(z,{onPress:n,children:s("ui.cancel")}),o.jsx(z,{accent:!0,isDisabled:!e.canSubmit,isPending:e.busy,onPress:()=>void e.submit(n),children:s("config.newSourceCreate")})]}),children:[e.problem&&o.jsx(le,{takeFocus:!0,children:e.problem.text},e.problem.id),o.jsxs("div",{className:"rp-list",children:[o.jsx("span",{className:"rp-label",children:s(e.choice?"config.newSourceNameHelp":"config.newSourceHelp")}),e.choices.length>1&&o.jsx(pe,{label:s("config.newSourcePattern"),items:e.choices.map(n=>({id:n.pattern,label:n.pattern})),value:e.choice?.pattern??"",onChange:e.setChoice,isDisabled:e.busy}),e.choice?o.jsx(G,{isDisabled:e.busy,label:s("config.newSourceName"),value:e.text,prefix:e.choice.prefix,suffix:e.choice.suffix,placeholder:"extra",spellCheck:!1,error:e.error,onChange:e.setText}):o.jsx(G,{isDisabled:e.busy,label:s("config.newSourcePath"),value:e.text,placeholder:"config.d/extra.dae",spellCheck:!1,error:e.error,onChange:e.setText}),e.unmatched&&o.jsx(le,{tone:"informative",children:s("config.newSourceUnmatched")})]})]})]})}function xs(t){const{canValidate:s,contentOffered:e}=t,n=F(),{writable:a,note:r,refused:l,shown:c,marks:f,text:i,outbounds:u,focus:g,dirty:d,conflict:v,keep:S,validate:w,save:b,cancel:x,change:k,view:C,busy:D,validating:h,saving:y,saveButton:N,validateDisabled:E,reason:R}=Gt(t);return o.jsxs(ue,{"aria-label":C.label,children:[o.jsx(Z,{reason:R,children:o.jsxs("div",{className:"rp-row rp-source-note",children:[o.jsx("span",{className:"rp-cluster",children:d?o.jsxs(o.Fragment,{children:[o.jsx(fe,{tone:"warn",children:n("config.unsaved")}),o.jsx("span",{className:"rp-label",children:n("config.unsavedHint")})]}):C.hasContent&&o.jsx("span",{className:"rp-label",children:r})}),(s||d)&&o.jsxs("span",{className:"rp-cluster nowrap",children:[s&&o.jsx(z,{isPending:h,isDisabled:E,onPress:()=>void w(),children:n("config.validate")}),d&&o.jsxs(o.Fragment,{children:[o.jsx(z,{isDisabled:D,onPress:x,children:n("ui.cancel")}),o.jsx(z,{accent:!0,isPending:y,isDisabled:N.disabled,tip:N.tip,onPress:()=>void b(),children:n("config.save")})]})]})]})}),v&&o.jsx(ve,{message:v,busy:D,keep:S}),c.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":n("config.diagnostics"),children:c.map((j,L)=>o.jsxs("div",{className:"rp-cluster",role:"listitem",children:[o.jsx($,{small:!0,tone:j.tone,children:j.detail}),o.jsx(z,{small:!0,quiet:!0,label:n("config.openSourceAt",{where:j.where}),onPress:()=>t.open(j.sourceId,j.line),children:n("config.openSource")})]},L))}),C.hasContent?o.jsx(be,{label:C.label,value:i,readOnly:!a||D,onChange:k,onReadOnlyAttempt:l,marks:f,focusLine:g,outbounds:u,onSave:d&&!D?()=>void b():void 0}):o.jsx(Cn,{children:n(e?"config.contentWithheld":"config.contentHidden")})]})}function ws(t){const{canValidate:s,open:e}=t,n=F(),{level:a,setLevel:r,selected:l,setSelected:c,shown:f,validate:i,summaryTone:u,summary:g,lastRun:d,validating:v,blocked:S,reason:w,levels:b}=Ut(t);return o.jsxs(o.Fragment,{children:[o.jsx(Z,{reason:s?w:null,children:o.jsxs("div",{className:"rp-toolbar",children:[o.jsx($,{small:!0,tone:u,children:g}),o.jsx("span",{className:"rp-label",children:d}),o.jsx("span",{className:"rp-grow"}),s&&o.jsxs(z,{isPending:v,isDisabled:S,onPress:i,children:[o.jsx(Nn,{className:"rp-spin-on-press"}),n("config.revalidate")]})]})}),o.jsx("span",{className:"rp-label",children:n("config.validateNote")}),o.jsx(Dn,{label:n("config.level"),value:a,onChange:r,items:b}),o.jsx(Ct,{label:n("config.diagnostics"),rows:f,height:360,selected:l,onSelect:c,detail:x=>o.jsxs("div",{className:"rp-cluster rp-config-diagnostics",children:[o.jsx($,{small:!0,tone:x.tone,children:x.detail}),o.jsx(z,{label:n("config.openSourceAt",{where:x.where}),onPress:()=>e(x.sourceId,x.line),children:n("config.openSource")})]}),empty:n("config.noDiagnostics"),cols:[{id:"level",label:n("config.level"),minWidth:96,grow:0,render:x=>o.jsx($,{small:!0,tone:x.tone,children:x.levelText})},{id:"where",label:n("config.where"),minWidth:150,grow:0,render:x=>o.jsx("span",{className:"rp-code",children:x.where})},{id:"message",label:n("config.message"),minWidth:240,grow:2,isRowHeader:!0,render:x=>o.jsx(We,{children:x.message})},{id:"code",label:n("config.code"),minWidth:140,drop:1,render:x=>o.jsx(Ge,{text:x.code})}]})]})}const ys=["global","bypass","gfw","mini","standard","full"],ze={global:["config.wizardGlobal","config.wizardGlobalHelp"],bypass:["config.wizardBypass","config.wizardBypassHelp"],gfw:["config.wizardGfw","config.wizardGfwHelp"],mini:["config.wizardMini","config.wizardMiniHelp"],standard:["config.wizardStandard","config.wizardStandardHelp"],full:["config.wizardFull","config.wizardFullHelp"]};function js({main:t,editor:s,onDone:e}){const n=F(),a=ne(),r=ee[a],[l,c]=m.useState(()=>t),f=Mn(l),i=l.content??"",[u,g]=m.useState(()=>ie(i)),d=m.useMemo(()=>ke(i,ie(i)),[i]),v=m.useMemo(()=>{try{return{text:f?ke(i,u):i,error:null}}catch(P){return{text:i,error:P}}},[f,i,u]),{text:S}=v,w=!!s.busy,b=v.error!==null||f===!0&&S!==d,x=b||f===!0&&!i.trim(),[k,C]=m.useState(null),D=()=>{c(t),g(ie(t.content??"")),C(null)},h=de(b,D);m.useEffect(()=>s.cancel,[s.cancel,h.revision]);const y=Ht(b,l,t),N=y==="conflict";Y(y==="follow"?t:null,P=>{P&&D()});const E=Bn(u.subscriptions),R=!!i.trim()||In(u),j=E&&R,L=P=>{C(null),g(B=>({...B,...P}))},A=(P,B)=>L({subscriptions:u.subscriptions.map((p,O)=>O===P?{...p,...B,raw:void 0}:p)}),I=async()=>{if(w||!j||N)return;if(v.error){H("negative",n("config.previewFailed"),{detail:Ie(v.error,n)});return}const P=await s.apply(l,S);if(P){if(P.diagnostics){C(P.diagnostics),H("negative",n("ui.writeInvalid",{n:P.diagnostics.filter(B=>B.level==="error").length}));return}H("positive",n("config.saved",{path:W})),h.clear(),e()}},W=Q(t,r,n).label,V=_t(u,a,n),M=(s.errorSource===l.id?s.diagnostics:null)??k??[],T=P=>Le(P.trim())?void 0:n("config.unquotable");return{state:u,text:S,busy:w,rows:V.rows,diagnostics:se(M,[t],r,n),defaultDnsError:T(u.defaultDns),chinaDnsError:T(u.chinaDns),groupUsedText:V.groupUsedText,templateHelp:u.rules==="keep"?null:n("config.wizardPresetHelp"),networkError:R?void 0:n("config.wizardNetworkError"),patch:L,setSubscription:A,apply:I,conflict:N?n("config.changedOnDisk"):null,keep:()=>c(t),discard:D,saveDisabled:!f||!j||w||!x||N,saving:s.busy==="save",saveReason:me({busy:w,complete:f,conflict:N,invalid:E?R?null:n("config.wizardNetworkError"):n("config.wizardSubsInvalid"),changed:x},n),writeHelp:i.trim()?n("config.wizardWriteHelp",{path:W}):null,showLan:!i.trim(),templates:[...i.trim()?[{id:"keep",label:n("config.wizardKeep"),desc:n("config.wizardKeepHelp")}]:[],...ys.map(P=>({id:P,label:n(ze[P][0]),desc:n(ze[P][1])}))],add:()=>L({subscriptions:[...u.subscriptions,{name:Wn(u.subscriptions),url:""}]}),remove:P=>L({subscriptions:u.subscriptions.filter((B,p)=>p!==P)})}}function ks(t){const s=F(),{state:e,text:n,busy:a,rows:r,diagnostics:l,defaultDnsError:c,chinaDnsError:f,groupUsedText:i,templateHelp:u,networkError:g,patch:d,setSubscription:v,apply:S,conflict:w,keep:b,discard:x,saveDisabled:k,saving:C,saveReason:D,writeHelp:h,showLan:y,templates:N,add:E,remove:R}=js(t);return o.jsxs(ue,{"aria-label":s("config.wizard"),children:[o.jsx("span",{className:"rp-label",children:s("config.wizardNote")}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardSubscriptions")}),o.jsxs("div",{className:"rp-list",children:[r.map(j=>o.jsxs("div",{className:j.raw===null?"rp-toolbar top rp-sub-row":"rp-toolbar top",children:[j.raw!==null?o.jsx(Ge,{text:j.raw,className:"rp-grow rp-config-raw"}):o.jsxs(o.Fragment,{children:[o.jsx(G,{isDisabled:a,label:s("config.wizardSubscriptionName"),value:j.name,width:140,error:j.nameError,onChange:L=>v(j.index,{name:L})}),o.jsx(G,{isDisabled:a,className:"rp-sub-url",label:s("config.wizardSubscription"),value:j.url,width:520,placeholder:"https://example.org/sub?token=…",error:j.error,description:j.description,onChange:L=>v(j.index,{url:L})})]}),o.jsx("span",{className:j.raw===null?"rp-field-row rp-sub-remove":void 0,children:o.jsx(z,{isDisabled:a,quiet:!0,small:!0,label:j.removeLabel,onPress:()=>R(j.index),children:o.jsx(Pn,{})})})]},j.index)),o.jsx("div",{children:o.jsx(z,{isDisabled:a,small:!0,onPress:E,children:s("config.wizardAddSubscription")})})]}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardTemplate")}),o.jsxs("div",{className:"rp-toolbar top",children:[o.jsx(pe,{isDisabled:a,label:s("config.wizardTemplate"),value:e.rules,onChange:j=>d({rules:j}),items:N}),y&&o.jsx(G,{isDisabled:a,label:s("config.wizardLan"),value:e.lanInterface,width:140,placeholder:"auto",onChange:j=>d({lanInterface:j})})]}),i&&o.jsx("span",{className:"rp-label",children:i}),u&&o.jsx("span",{className:"rp-label",children:u}),y&&o.jsxs("div",{className:"rp-toolbar top",children:[o.jsx(G,{isDisabled:a,label:s("config.wizardListenerPort"),value:e.listenerPort,width:140,onChange:j=>d({listenerPort:j}),error:g}),o.jsx(G,{isDisabled:a,label:s("config.wizardDefaultDns"),value:e.defaultDns,error:c,onChange:j=>d({defaultDns:j})}),o.jsx(G,{isDisabled:a,label:s("config.wizardChinaDns"),value:e.chinaDns,error:f,onChange:j=>d({chinaDns:j})})]}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardPreview")}),o.jsx(be,{label:s("config.wizardPreview"),value:n,readOnly:!0,compact:!0}),l.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":s("config.diagnostics"),children:l.map(j=>o.jsx("div",{role:"listitem",children:o.jsx($,{small:!0,tone:j.tone,children:j.detail})},j.id))}),w&&o.jsx(ve,{message:w,busy:a,keep:b,discard:x}),o.jsx(Z,{reason:D,children:o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(z,{accent:!0,isDisabled:k,isPending:C,onPress:()=>void S(),children:s("config.save")}),h&&o.jsx("span",{className:"rp-label",children:h})]})})]})}function As(t){const s=F(),{error:e,reload:n,loading:a,ready:r,metadata:l,redacted:c,tabs:f,tab:i,setTab:u,selectedId:g,select:d,sourceProps:v,newSourceProps:S,wizardProps:w,validateProps:b,modulesProps:x,sourceModel:k,sourceOptions:C,exportSource:D,summaryTone:h,summaryText:y}=Kt(t),N={modules:x&&o.jsx(hs,{...x}),setup:w&&o.jsx(ks,{...w}),source:o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"rp-toolbar",children:[o.jsxs("span",{className:"rp-cluster nowrap rp-source-pick",children:[o.jsx(pe,{side:!0,cut:"start",label:s("config.source"),value:g,onChange:d,items:C}),k&&o.jsxs(o.Fragment,{children:[k.readOnly&&o.jsxs("span",{className:"rp-help-row",children:[o.jsx(fe,{children:k.readOnly.label}),k.readOnly.help&&o.jsx(En,{...k.readOnly.help})]}),o.jsx(We,{className:"rp-label",text:k.loaded,children:k.facts})]})]}),(S||k?.hasContent)&&o.jsxs("span",{className:"rp-cluster nowrap",children:[S&&o.jsx(vs,{...S}),k?.hasContent&&o.jsxs(z,{onPress:D,children:[o.jsx(zn,{}),s("config.export")]})]})]}),k?.hasContent&&o.jsx("span",{className:"rp-label",children:s("config.exportWarning")}),v&&o.jsx(xs,{...v},k.id)]}),validate:b&&o.jsx(ws,{...b})};return o.jsxs("div",{className:"rp-page",children:[o.jsx(Rn,{error:e,onRetry:n}),a&&o.jsx(Tn,{}),r&&o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(Ln,{row:!0,items:l}),o.jsx($,{small:!0,tone:h,children:y}),c&&o.jsx($,{small:!0,tone:"muted",children:s("config.redacted")})]}),r&&o.jsx(Fn,{label:s("nav.config"),value:i,onChange:u,items:f.map(E=>({...E,content:N[E.id]}))})]})}export{As as Config};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Config-BVUCd2Cc.js b/luci-app-honk/root/etc/honk/dashboard/assets/Config-BVUCd2Cc.js
deleted file mode 100644
index ba53ae1c3..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Config-BVUCd2Cc.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import{r as h,j as o}from"./vendor-react-Bf71BWbF.js";import{j as Ne,q as He,c$ as $e,p as Ie,u as R,V as Me,ah as Te,ag as Oe,W as ie,d0 as We,cA as W,ae as Be,d1 as Ve,d2 as Pe,d3 as Ge,U as ze,h as me,F as se,D as Ke,_ as q,d4 as Ue,co as le,A as ee,b2 as V,X as J,b0 as _,a as Ee,ax as ce,T as O,B as T,a7 as qe,aT as de,at as L,d5 as Je,cE as Re,$ as Qe,a5 as Xe,a1 as he,b5 as Ye,b4 as Ze,d6 as en,cD as nn,Q as te,d7 as ue,d8 as sn,d9 as Le,x as tn,da as on,db as rn,dc as an,t as ln,v as cn,dd as dn,ay as pe,aw as un,E as pn,b as fn,au as gn,bc as mn,bo as hn,aS as bn,av as vn,M as xn,I as be,a8 as wn,L as yn}from"./index-zQjLFfuj.js";import{d as jn,s as Sn,D as Fe}from"./DaeCode-B4MDdwFy.js";import{D as kn}from"./Table-DLlwyNFJ.js";import{A as Cn}from"./AddCircle-DSsJ-CRu.js";import{S as Dn,a as Nn,C as oe,E as H,b as Y,l as Mn,h as Tn,c as Pn,d as zn,e as En,r as Rn,f as Ln,g as Fn,i as _n,j as An,k as Hn,m as $n,s as In,n as On,t as Wn,o as Bn,p as Vn,q as Gn,u as Kn,v as Un,w as qn,x as Jn,T as Qn,y as Xn,z as Yn,D as Z,R as Zn,A as es,B as ns,F as ss,H as ts,G as I}from"./vendor-editor-BYSNX95r.js";import{r as os,d as rs,a as as,t as ve,b as is,w as xe,v as ls,c as we,n as cs}from"./setup-BqwQo7FE.js";import{g as ds}from"./policyText-IIH31itq.js";import{a as us,s as ps,c as fs}from"./nav-BeFLfZq8.js";import{d as gs}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";const ms=Dn.define({name:"dae",languageData:{commentTokens:{line:"#"},closeBrackets:{brackets:["(","{","'",'"']}},startState:Sn,token:jn}),hs=["global","subscription","node","group","dns","routing"].map(n=>({label:n,type:"keyword"})),bs=Ie.map(n=>({label:n,type:"property",apply:n+": "})),vs=["domain","dip","sip","dport","sport","l4proto","ipversion","pname","mac","dscp","qname","qtype","upstream"].map(n=>({label:n,type:"function",apply:n+"("})),xs=["geosite","geoip","suffix","full","keyword","regex"].map(n=>({label:n,type:"constant",apply:n+":"})),ye=$e.map(n=>({label:n,type:"constant"})),ws=He.map(n=>({label:n,type:"keyword"})),ys=[{label:"fallback",type:"keyword",apply:"fallback: "},{label:"include",type:"keyword",apply:"include "}];function js(n,s){const e=n.matchBefore(/[\w.-]*/);if(!e)return null;const t=n.state.doc.lineAt(n.pos),a=t.text.slice(0,n.pos-t.from),r=/->\s*[\w.-]*$/.test(a)||/^\s*fallback:\s*[\w.-]*$/.test(a);if(e.from===e.to&&!n.explicit&&!r)return null;const l=n.state.doc.sliceString(0,n.pos),{blocks:p,tokens:c}=Ne(l),d=c.at(-1);if(d?.to===n.pos&&(d.kind==="quoted"||d.kind==="comment"))return null;const i=p.find(b=>b.close===n.pos)?.name;let f;if(r)f=[...s().map(b=>({label:b.name,apply:b.written,type:"variable"})),...ws];else if(/\b(domain|dip|sip|qname)\(\s*[\w.-]*$/.test(a))f=xs;else if(i===void 0)f=hs.map(b=>({...b,apply:(v,x,k,C)=>{const j=b.label+` {
-
-}`;v.dispatch({changes:{from:k,to:C,insert:j},selection:{anchor:k+b.label.length+4}})}}));else if(i==="routing"||i==="dns")f=[...vs,...ys];else if(i==="global")f=bs;else if(i==="group")f=/\bpolicy\s*:\s*[\w.-]*$/.test(a)?ye:[...ye.map(b=>({...b,apply:"policy: "+b.label})),{label:"filter",type:"property",apply:"filter: "}];else return null;return{from:e.from,options:f,validFor:/^[\w.-]*$/}}function Ss(n){return Nn({override:[s=>js(s,n)]})}function ks(n,s){return s.filter(e=>e.line>=1&&e.line<=n.doc.lines).map(e=>{const t=n.doc.line(e.line),a=Math.max(0,(e.column??1)-1),r=new TextEncoder().encode(t.text);let l=0;for(let c=0;ca)break;c+=d,l+=d===4?2:1}return{from:t.from+l,to:t.to,severity:e.level,message:e.message}})}const Cs=[["Completions","cm.completions"],["Find","cm.find"],["Replace","cm.replace"],["next","cm.next"],["previous","cm.previous"],["all","cm.all"],["match case","cm.matchCase"],["regexp","cm.regexp"],["by word","cm.byWord"],["replace","cm.replaceOne"],["replace all","cm.replaceAll"],["close","close"],["Go to line","cm.gotoLine"],["go","cm.go"],["current match","cm.currentMatch"],["replaced $ matches","cm.replacedMatches"],["replaced match on line $","cm.replacedOnLine"],["on line","cm.onLine"],["Selection deleted","cm.selectionDeleted"],["Control character","cm.controlCharacter"]],je=n=>Y.phrases.of(Object.fromEntries(Cs.map(([s,e])=>[s,n(e)]))),Ds=H.theme({"&":{backgroundColor:"var(--rp-base)",color:"var(--rp-text)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",fontSize:"var(--rp-text-sm)"},"&.cm-focused":{outline:"none",borderColor:"var(--rp-accent)",boxShadow:"0 0 0 1px var(--rp-accent)"},".cm-scroller":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace",lineHeight:"20px",maxHeight:"70vh",fontVariantLigatures:"none"},".cm-content":{padding:"8px 0",caretColor:"var(--rp-text)"},".cm-line":{padding:"0 12px"},".cm-gutters":{backgroundColor:"var(--rp-base)",color:"var(--rp-muted)",border:"none"},".cm-lineNumbers .cm-gutterElement":{padding:"0 8px 0 12px",minWidth:"40px"},".cm-activeLine":{backgroundColor:"color-mix(in srgb, var(--rp-hl-med) 60%, transparent)"},".cm-activeLineGutter":{backgroundColor:"transparent",color:"var(--rp-text)"},".cm-selectionBackground, &.cm-focused .cm-selectionBackground, ::selection":{backgroundColor:"var(--rp-hl-high)"},".cm-cursor":{borderLeftColor:"var(--rp-text)"},".cm-matchingBracket":{backgroundColor:"color-mix(in srgb, var(--rp-accent) 20%, transparent)",outline:"none"},".cm-selectionMatch":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 25%, transparent)"},".cm-tooltip.cm-tooltip-lint":{backgroundColor:"var(--rp-text)",color:"var(--rp-on-text)",border:"none",borderRadius:"var(--rp-r-sm)",padding:"2px 0"},".cm-tooltip-lint .cm-diagnostic":{border:"none",padding:"2px 8px",fontSize:"var(--rp-text-xs)",lineHeight:"16px",fontFamily:"inherit"},".cm-tooltip-lint .cm-diagnosticText":{color:"inherit"},".cm-diag-line-error":{backgroundColor:"color-mix(in srgb, var(--rp-negative) 14%, transparent)"},".cm-diag-line-warning":{backgroundColor:"color-mix(in srgb, var(--rp-notice) 16%, transparent)"},".cm-diag-line-info":{backgroundColor:"color-mix(in srgb, var(--rp-foam) 14%, transparent)"},".cm-lintRange-error":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-negative)",textUnderlineOffset:"3px"},".cm-lintRange-warning":{backgroundImage:"none",textDecoration:"underline wavy var(--rp-notice)",textUnderlineOffset:"3px"},".cm-lintRange-info":{backgroundImage:"none",textDecoration:"underline dotted var(--rp-foam)",textUnderlineOffset:"3px"},".cm-tooltip":{backgroundColor:"var(--rp-surface)",border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-md)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]":{backgroundColor:"var(--rp-selected)",color:"var(--rp-text)"},".cm-tooltip.cm-tooltip-autocomplete > ul":{fontFamily:"ui-monospace, 'SF Mono', Menlo, Consolas, 'JetBrains Mono', 'Fira Code', 'DejaVu Sans Mono', 'Liberation Mono', 'Noto Sans Mono', monospace"},".cm-panels":{backgroundColor:"var(--rp-surface)",color:"var(--rp-text)"},".cm-panels-bottom":{borderTop:"1px solid var(--rp-hl-med)"},".cm-textfield":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundColor:"var(--rp-base)",color:"var(--rp-text)"},".cm-button":{border:"1px solid var(--rp-hl-high)",borderRadius:"var(--rp-r-sm)",backgroundImage:"none",backgroundColor:"var(--rp-overlay)",color:"var(--rp-text)"}}),Ns=ts.define([{tag:I.comment,color:"var(--rp-code-comment)"},{tag:I.keyword,color:"var(--rp-code-keyword)",fontWeight:"700"},{tag:I.string,color:"var(--rp-code-string)"},{tag:I.number,color:"var(--rp-code-number)"},{tag:I.propertyName,color:"var(--rp-code-propertyName)"},{tag:I.variableName,color:"var(--rp-code-variableName)"},{tag:I.operator,color:"var(--rp-code-operator)"},{tag:I.punctuation,color:"var(--rp-code-punctuation)"}]),Ms=es.of((n,s)=>{const e=n.lineAt(s,-1),t=e.from>0?n.lineAt(e.from-1,-1):null;if(!t)return 0;const a=/^\s*/.exec(t.text)[0].length,r=/\{\s*(#.*)?$/.test(t.text),l=/^\s*\}/.test(e.text);return Math.max(0,a+(r?2:0)-(l?2:0))}),_e=ss.define(),Ts={error:Z.line({class:"cm-diag-line cm-diag-line-error"}),warning:Z.line({class:"cm-diag-line cm-diag-line-warning"}),info:Z.line({class:"cm-diag-line cm-diag-line-info"})},Ps=Yn.define({create:()=>Z.none,update(n,s){let e=n.map(s.changes);for(const t of s.effects){if(!t.is(_e))continue;const a=new Zn,r={error:0,warning:1,info:2},l=new Map;for(const p of t.value){if(p.line<1||p.line>s.state.doc.lines)continue;const c=l.get(p.line);(!c||r[p.level]c-d)){const c=s.state.doc.line(p).from;a.add(c,c,Ts[l.get(p).level])}e=a.finish()}return e},provide:n=>H.decorations.from(n)}),zs=[],Se=ns.define();function fe({value:n,onChange:s,readOnly:e=!1,marks:t=zs,focusLine:a,label:r,outbounds:l,onSave:p,compact:c}){const d=h.useRef(null),i=h.useRef(null),f=h.useRef(s),b=h.useRef(l),v=h.useRef(p);h.useEffect(()=>{f.current=s,b.current=l,v.current=p});const x=h.useRef(new oe),k=R(),C=h.useRef(new oe),j=h.useRef(new oe);return h.useLayoutEffect(()=>{const g=new H({parent:d.current,state:Y.create({doc:n,extensions:[Mn(),Tn(),Pn(),zn(),En(),Rn(),Ln(),Ps,Fn(),_n(),An(),Hn.of(" "),$n(),Ms,Ss(()=>b.current?.()??[]),ms,In(Ns),Ds,On.of([{key:"Mod-s",run:()=>(v.current?.(),!0)},{key:"Mod-/",run:Wn},{key:"Mod-g",run:Bn},...Vn,...Gn,...Kn,...Un,...qn,Jn]),x.current.of([Y.readOnly.of(e),H.editable.of(!e)]),C.current.of(je(k)),j.current.of(H.contentAttributes.of({"aria-label":r,tabindex:"0"})),H.updateListener.of(m=>{m.docChanged&&!m.transactions.some(S=>S.annotation(Se))&&f.current?.(m.state.doc.toString())})]})});return i.current=g,()=>{g.destroy(),i.current=null}},[]),h.useEffect(()=>{const g=i.current;g&&g.dispatch({effects:x.current.reconfigure([Y.readOnly.of(e),H.editable.of(!e)])})},[e]),h.useEffect(()=>{i.current?.dispatch({effects:C.current.reconfigure(je(k))})},[k]),h.useEffect(()=>{i.current?.dispatch({effects:j.current.reconfigure(H.contentAttributes.of({"aria-label":r,tabindex:"0"}))})},[r]),h.useEffect(()=>{const g=i.current;!g||g.state.doc.toString()===n||g.dispatch({changes:{from:0,to:g.state.doc.length,insert:n},annotations:[Se.of(!0),Qn.addToHistory.of(!1)]})},[n]),h.useEffect(()=>{const g=i.current;if(!g)return;const m=Xn(g.state,ks(g.state,t)),S=Array.isArray(m.effects)?m.effects:m.effects?[m.effects]:[];g.dispatch({...m,effects:[...S,_e.of(t)]})},[t]),h.useEffect(()=>{const g=i.current;if(!g||!a||a<1||a>g.state.doc.lines)return;const m=g.state.doc.line(a);g.dispatch({selection:{anchor:m.from},effects:H.scrollIntoView(m.from,{y:"center"})}),g.focus()},[a]),o.jsx("div",{className:c?"rp-editor compact":"rp-editor",ref:d})}const Es=["global","subscription","node","group","dns","routing"];function ke(n,s){return`${W(n)}:${s.line+1}-${s.endLine+1}`}function Rs(n,s,e){return n.slice(0,s.from)+e+n.slice(s.to)}function Ls(n,s,e,t){const a=e.line+t.split(`
-`).length;return n.filter(r=>r.source_id===s&&r.line!==null&&r.line>e.line&&r.line<=a).map(r=>({line:r.line-e.line,column:r.column,level:r.level,message:r.message}))}function Fs(n,s){return n.filter(e=>e.source_id===s&&e.line!==null).map(e=>({line:e.line,column:e.column,level:e.level,message:e.message}))}function re(n,s,e){return e.filter(t=>t.from>s.open&&t.to<=s.close&&t.depth===s.depth+1&&t.parens===0&&t.kind==="text"&&n.slice(t.from,t.to)==="->").length}function Ce(n,s,e){const t=s.filter(a=>a.from>n.open&&a.to<=n.close&&a.depth===n.depth+1&&a.parens===0&&(a.kind==="quoted"||a.kind==="text")&&!e.some(r=>a.from>=r.from&&a.to<=r.to));return e.length+t.length}function _s(n,s,e,t,a,r){const l=se(s,e,t);switch(n){case"global":return r("config.moduleSettings",{n:l.length});case"subscription":return r("config.moduleSubscriptions",{n:Ce(e,t,l)});case"node":return r("config.moduleNodes",{n:Ce(e,t,l)});case"group":return r("config.moduleGroups",{n:e.children.length,policies:ze(a,e.children.map(p=>{const c=se(s,p,t).find(i=>i.name==="policy")?.value;if(!c)return p.name;const d=Ke(c);return r("ui.valuePair",{label:p.name,value:d?ds({kind:d,native:c},r).label:c})}))});case"dns":{const p=e.children.filter(d=>d.name==="upstream"),c=e.children.filter(d=>d.name==="routing").flatMap(d=>d.children);return[r("config.moduleDnsUpstreams",{n:p.reduce((d,i)=>d+se(s,i,t).length,0)}),r("config.moduleDnsRequests",{n:c.filter(d=>d.name==="request").reduce((d,i)=>d+re(s,i,t),0)}),r("config.moduleDnsResponses",{n:c.filter(d=>d.name==="response").reduce((d,i)=>d+re(s,i,t),0)})].join(r("ui.listSeparator"))}case"routing":{const p=r("config.moduleRules",{n:re(s,e,t)}),c=l.find(d=>d.name==="fallback")?.value;return c?p+r("ui.separator")+r("ui.valuePair",{label:"fallback",value:c}):p}}}function As(n,s,e){const a=n.filter(c=>c.kind==="main"||c.kind==="include").map(c=>({source:c,...Ne(c.content??"")})),r=n.find(c=>c.kind==="main")??null,l=Es.flatMap(c=>{const d=c==="group"?me("policies"):c==="node"||c==="subscription"?me("nodes"):null,i=a.flatMap(({source:f,blocks:b,tokens:v})=>b.filter(x=>x.name===c).map((x,k)=>({id:`${f.id}:${c}:${k}`,kind:c,source:f,block:x,href:d,range:ke(f,x),summary:_s(c,f.content,x,v,s,e),note:null})));return i.length||r&&r.content===void 0?i:[{id:c,kind:c,source:r,block:null,href:d,range:r?W(r):"config.dae",summary:r?.content===void 0?"":r.writable?e("config.moduleAbsent",{file:W(r)}):e("config.moduleAbsentReadOnly"),note:r?.content===void 0?e("config.contentWithheld"):null}]}),p=a.flatMap(({source:c,blocks:d})=>c.content===void 0?[{id:c.id,kind:W(c),source:c,block:null,href:null,range:W(c),summary:"",note:e("config.contentWithheld")}]:d.filter(i=>i.name==="experimental"&&i.children.some(f=>f.name==="native_api")).map((i,f)=>({id:`${c.id}:experimental:${f}`,kind:"experimental.native_api",source:c,block:null,href:null,range:ke(c,i),summary:"",note:e("config.incomplete")})));return[...l,...p]}function G(n,s,e){const t=Me(us,n.kind,e);return{id:n.id,label:We(n)?`${t} ${n.id.slice(0,8)}`:n.path,kind:t,editable:e(n.writable?"config.editable":"config.readOnly"),tone:n.writable?"ok":"muted",facts:e("config.sourceFacts",{lines:ie(n.line_count,s),size:Oe(String(n.bytes),s),time:Te(n.loaded_at,s)}),hasContent:n.content!==void 0}}const Hs={error:"err",warning:"warn",info:"info"},$s={error:"config.level.error",warning:"config.level.warning",info:"config.level.info"};function ne(n,s,e,t){const a=new Map(s.map(l=>[l.id,W(l)])),r=new Map;for(const l of n){const p=JSON.stringify([l.level,l.source_id,l.line,l.column,l.code,l.message]),c=r.get(p);c?c.count++:r.set(p,{item:l,count:1})}return[...r.values()].map(({item:l,count:p},c)=>{const d=a.get(l.source_id)??l.source_id,i=Be(l.code,l.message,t),f=p>1?t("config.repeated",{text:i,n:ie(p,e)}):i,b=Ve(l.code)?t("config.backendDetail",{text:f,message:l.message}):f;return{id:String(c),level:l.level,tone:Hs[l.level],levelText:Me($s,l.level,t),sourceId:l.source_id,line:l.line,where:l.line===null?d:`${d}:${l.line}`,message:f,code:l.code,detail:l.line===null?b:t("config.atFile",{file:d,line:ie(l.line,e),message:b}),count:p}})}function ae(n){return{...os(n),rules:n.trim()?"keep":rs}}function Is(n,s,e){return{groupUsedText:n.rules==="keep"?null:ve[n.rules].groups.length?e("config.wizardNamedGroups",{names:ze(s,ve[n.rules].groups.map(t=>t.name))}):e("config.wizardGroupUsed",{name:n.group??is}),rows:n.subscriptions.flatMap((t,a)=>t.raw!==void 0&&!t.raw.trim()?[]:[{index:a,name:t.name,url:t.url,raw:t.raw!==void 0&&!t.name?t.raw.trim():null,nameError:t.raw===void 0&&!Ge(t.name.trim())?e("config.unquotable"):void 0,error:t.url!==""&&!as(t.url)?e("config.wizardSubscriptionHelp"):t.raw===void 0&&!Pe(t.url.trim())?e("config.unquotable"):void 0,description:a===0?e("config.wizardSubscriptionHelp"):void 0,removeLabel:e("config.wizardRemove",{name:t.name||t.raw?.trim()||""})}])}}const Os=["global","bypass","gfw","mini","standard","full"],De={global:["config.wizardGlobal","config.wizardGlobalHelp"],bypass:["config.wizardBypass","config.wizardBypassHelp"],gfw:["config.wizardGfw","config.wizardGfwHelp"],mini:["config.wizardMini","config.wizardMiniHelp"],standard:["config.wizardStandard","config.wizardStandardHelp"],full:["config.wizardFull","config.wizardFullHelp"]};function Ws({main:n,editor:s,onDone:e}){const t=R(),a=q(),r=J[a],[l,p]=h.useState(()=>n),c=Ue(l),d=l.content??"",[i,f]=h.useState(()=>ae(d)),b=h.useMemo(()=>xe(d,ae(d)),[d]),v=h.useMemo(()=>{try{return{text:c?xe(d,i):d,error:null}}catch(D){return{text:d,error:D}}},[c,d,i]),{text:x}=v,k=!!s.busy,C=v.error!==null||c===!0&&x!==b,j=C||c===!0&&!d.trim(),[g,m]=h.useState(null),S=le(C,()=>{p(n),f(ae(n.content??"")),m(null)});h.useEffect(()=>s.cancel,[s.cancel,S.revision]);const N=s.error instanceof ee&&s.error.status===412;V(N&&n.content_sha256!==l.content_sha256?n:null,D=>{D&&p(D)});const E=ls(i.subscriptions)&&(!!d.trim()||we(i)),w=D=>{m(null),f(F=>({...F,...D}))},P=(D,F)=>w({subscriptions:i.subscriptions.map(($,Q)=>Q===D?{...$,...F,raw:void 0}:$)}),A=async()=>{if(k||!E)return;if(v.error){_("negative",t("config.previewFailed"),{detail:Ee(v.error,t)});return}const D=await s.apply(l,x);if(D){if(D.diagnostics){m(D.diagnostics),_("negative",t("ui.writeInvalid",{n:D.diagnostics.filter(F=>F.level==="error").length}));return}_("positive",t("config.saved",{path:y})),S.clear(),e()}},y=G(n,r,t).label,M=Is(i,a,t),K=(s.errorSource===l.id?s.diagnostics:null)??g??[],B=D=>Pe(D.trim())?void 0:t("config.unquotable");return{state:i,text:x,busy:k,rows:M.rows,diagnostics:ne(K,[n],r,t),defaultDnsError:B(i.defaultDns),chinaDnsError:B(i.chinaDns),groupUsedText:M.groupUsedText,templateHelp:i.rules==="keep"?null:t("config.wizardPresetHelp"),networkError:!d.trim()&&!we(i)?t("config.wizardNetworkError"):void 0,patch:w,setSubscription:P,apply:A,saveDisabled:!c||!E||k||!j,saving:s.busy==="save",saveTip:c===!1?t("config.incomplete"):void 0,writeHelp:d.trim()?t("config.wizardWriteHelp",{path:y}):null,showLan:!d.trim(),templates:[...d.trim()?[{id:"keep",label:t("config.wizardKeep"),desc:t("config.wizardKeepHelp")}]:[],...Os.map(D=>({id:D,label:t(De[D][0]),desc:t(De[D][1])}))],add:()=>w({subscriptions:[...i.subscriptions,{name:cs(i.subscriptions),url:""}]}),remove:D=>w({subscriptions:i.subscriptions.filter((F,$)=>$!==D)})}}function Bs(n){const s=R(),{state:e,text:t,busy:a,rows:r,diagnostics:l,defaultDnsError:p,chinaDnsError:c,groupUsedText:d,templateHelp:i,networkError:f,patch:b,setSubscription:v,apply:x,saveDisabled:k,saving:C,saveTip:j,writeHelp:g,showLan:m,templates:S,add:N,remove:E}=Ws(n);return o.jsxs(ce,{"aria-label":s("config.wizard"),children:[o.jsx("span",{className:"rp-label",children:s("config.wizardNote")}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardSubscriptions")}),o.jsxs("div",{className:"rp-list",children:[r.map(w=>o.jsxs("div",{className:w.raw===null?"rp-toolbar top rp-sub-row":"rp-toolbar top",children:[w.raw!==null?o.jsx(Fe,{text:w.raw,className:"rp-grow rp-config-raw"}):o.jsxs(o.Fragment,{children:[o.jsx(O,{isDisabled:a,label:s("config.wizardSubscriptionName"),value:w.name,width:140,error:w.nameError,onChange:P=>v(w.index,{name:P})}),o.jsx(O,{isDisabled:a,className:"rp-sub-url",label:s("config.wizardSubscription"),value:w.url,width:520,placeholder:"https://example.org/sub?token=…",error:w.error,description:w.description,onChange:P=>v(w.index,{url:P})})]}),o.jsx("span",{className:w.raw===null?"rp-field-row rp-sub-remove":void 0,children:o.jsx(T,{isDisabled:a,quiet:!0,small:!0,label:w.removeLabel,onPress:()=>E(w.index),children:o.jsx(qe,{})})})]},w.index)),o.jsx("div",{children:o.jsx(T,{isDisabled:a,small:!0,onPress:N,children:s("config.wizardAddSubscription")})})]}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardTemplate")}),o.jsxs("div",{className:"rp-toolbar top",children:[o.jsx(de,{isDisabled:a,label:s("config.wizardTemplate"),value:e.rules,onChange:w=>b({rules:w}),items:S}),m&&o.jsx(O,{isDisabled:a,label:s("config.wizardLan"),value:e.lanInterface,width:140,placeholder:"auto",onChange:w=>b({lanInterface:w})})]}),d&&o.jsx("span",{className:"rp-label",children:d}),i&&o.jsx("span",{className:"rp-label",children:i}),m&&o.jsxs("div",{className:"rp-toolbar top",children:[o.jsx(O,{isDisabled:a,label:s("config.wizardListenerPort"),value:e.listenerPort,width:140,onChange:w=>b({listenerPort:w}),error:f}),o.jsx(O,{isDisabled:a,label:s("config.wizardDefaultDns"),value:e.defaultDns,error:p,onChange:w=>b({defaultDns:w})}),o.jsx(O,{isDisabled:a,label:s("config.wizardChinaDns"),value:e.chinaDns,error:c,onChange:w=>b({chinaDns:w})})]}),o.jsx("h3",{className:"rp-h3",children:s("config.wizardPreview")}),o.jsx(fe,{label:s("config.wizardPreview"),value:t,readOnly:!0,compact:!0}),l.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":s("config.diagnostics"),children:l.map(w=>o.jsx("div",{role:"listitem",children:o.jsx(L,{small:!0,tone:w.tone,children:w.detail})},w.id))}),o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(T,{accent:!0,isDisabled:k,isPending:C,tip:j,onPress:()=>void x(),children:s("config.save")}),g&&o.jsx("span",{className:"rp-label",children:g})]})]})}function ge(n,s,e){const t=e?.id,a=e?.content;return h.useMemo(()=>{const r=n.filter(l=>l.kind==="main"||l.kind==="include");return r.some(l=>s(l)===void 0)?null:Je(r.filter(l=>s(l)),t!==void 0&&a!==void 0?{id:t,content:a}:void 0)},[n,s,t,a])}const Vs=600,Gs=()=>{};function Ae(n,s){const{validate:e,cancel:t}=Re(Gs);h.useEffect(()=>{if(!n)return;let a=!0;const r=setTimeout(()=>{e({sources:n,mode:"full"}).then(l=>{a&&l&&s(l.diagnostics)})},Vs);return()=>{a=!1,clearTimeout(r),t()}},[n,e,t,s])}function Ks(n){const s=R(),e=Re(n),t=h.useMemo(()=>e.error instanceof ee&&e.error.status===422?e.error.details?.diagnostics??[]:null,[e.error]);return h.useEffect(()=>{if(e.error)if(t){const a=en(t);_("negative",a?s("config.writeRestart",{n:a}):s("ui.writeInvalid",{n:t.filter(r=>r.level==="error").length}))}else nn(e.error,s,s("ui.writeFailed"))},[e.error,t,s]),{...e,diagnostics:t}}function Us({go:n,query:s}){const e=R(),t=J[q()],a=Qe().data?.resources,r=Xe(he(a,"config",{whileLoading:!0})),l=Ks(r.refetch),p=h.useMemo(()=>new URLSearchParams(s),[s]),c=h.useMemo(()=>r.data?.sources??[],[r.data]),d=c.find(y=>y.kind==="main")??null,i=c.find(y=>y.id===p.get("source"))??c[0]??null,f=i?.id??null,b=y=>n("config",te(s,{source:y,line:null})),v=(y,M)=>n("config",te(s,{tab:"source",source:y,line:M===null?null:String(M)})),x=Number(p.get("line"))||null,k=h.useMemo(()=>(r.data?.diagnostics??[]).filter(y=>y.source_id===f),[r.data,f]),C=h.useMemo(()=>{const y=r.data?.diagnostics??[];return{error:y.filter(M=>M.level==="error").length,warning:y.filter(M=>M.level==="warning").length}},[r.data]),j=ps(a,d),g=fs(j),m=he(a,"config_validate",{whileLoading:!1})&&(a?.config_validate.modes??[]).includes("full"),S=p.has("source")||d?.content===void 0?"source":!d.content.trim()&&j?"setup":"modules",N=Ye(s,g.map(y=>y.id),S),E=i?{source:i,sources:c,open:v,diagnostics:k,canValidate:m,canWrite:a?.config.writable===!0&&i.writable,contentOffered:a?.config.content===!0,editor:l,focusLine:x}:null,w=j&&d?{main:d,editor:l,onDone:()=>n("config",te(s,{tab:"source",source:d.id}))}:null,P=a?.config.create===!0&&a.config.writable===!0?{sources:c,contentOffered:a.config.content===!0,refetch:r.refetch,open:y=>v(y,null)}:null,A=r.data?{config:r.data,editor:l,canValidate:m,open:v}:null;return{error:r.error,reload:r.refetch,loading:r.loading&&!r.data,ready:!!r.data,metadata:r.data?[[e("config.generation"),r.data.generation_id],[e("config.revision"),r.data.revision]]:[],redacted:!!r.data?.secrets_redacted,tabs:g.map(y=>({id:y.id,label:e(y.titleKey)})),tab:N,setTab:y=>n("config",Ze(s,y,null)),selectedId:f??"",select:b,sourceProps:E,newSourceProps:P,wizardProps:w,modulesProps:r.data?{config:r.data,editor:l,canWrite:a?.config.writable===!0,canValidate:m,open:v}:null,validateProps:A,sourceModel:i?G(i,t,e):null,sourceOptions:c.map(y=>{const M=G(y,t,e);return{id:M.id,label:M.label,desc:M.kind}}),exportSource:()=>{i?.content!==void 0&&gs(W(i),i.content,"text/plain;charset=utf-8")},summaryTone:C.error?"err":C.warning?"warn":"ok",summaryText:C.error?e("config.errors",{n:C.error}):C.warning?e("config.warnings",{n:C.warning}):e("config.clean")}}function qs({source:n,sources:s,diagnostics:e,canValidate:t,editor:a,focusLine:r}){const l=R(),p=J[q()],[c,d]=h.useState(null),[i,f]=h.useState(null),b=ue(s),v=b(n),x=c!==null,k=a.error instanceof ee&&a.error.status===412&&a.errorSource===n.id&&c?.origin.id===n.id;V(k&&n.content_sha256!==c.origin.content_sha256?n:null,u=>{u&&d(z=>z&&{...z,origin:u})});const j=(a.errorSource===n.id?a.diagnostics:null)??i??e,g=h.useMemo(()=>Fs(j,n.id),[j,n.id]),m=c?.text??n.content??"",S=()=>Le(s,{id:n.id,content:m}),[N,E]=h.useState(null);V(r,()=>E(null));const w=x&&c.text!==n.content,P=le(w,()=>{d(null),f(null)});h.useEffect(()=>a.cancel,[a.cancel,P.revision]);const A=c?.text,y=ge(s,b,{id:n.id,content:m});Ae(t&&A!==void 0?y:null,f);const M=(u,z=!0)=>{f(u.diagnostics);const X=u.diagnostics.find(U=>U.source_id===n.id&&U.level==="error"&&U.line!==null);return E(X?X.line:null),u.valid?z&&_("positive",l("config.valid")):_("negative",l("config.invalid",{n:u.diagnostics.filter(U=>U.level==="error").length})),u.valid},K=async()=>{if(!y)return!1;const u=await a.validate({sources:y,mode:"full"});return u?M(u):!1},B=async()=>{if(c===null||a.busy)return;const u=await a.apply(c.origin,c.text);if(f(null),!!u){if(u.diagnostics){M({valid:!1,diagnostics:u.diagnostics},!1);return}_("positive",l("config.saved",{path:G(n,p,l).label})),P.clear(),d(null)}},D=()=>d({text:n.content??"",origin:n}),F=()=>{d(null),f(null)},$=u=>d(z=>z&&{...z,text:u}),Q=G(n,p,l);return{editing:x,shown:ne(j,s,p,l),marks:g,text:m,outbounds:S,focus:N??r,dirty:w,validate:K,save:B,edit:D,cancel:F,change:$,view:Q,busy:!!a.busy,validating:a.busy==="validate",saving:a.busy==="save",saveTip:l(sn?"config.saveShortcutMac":"config.saveShortcut"),validateDisabled:!!a.busy||!y,validateTip:y?void 0:l("config.incomplete"),editDisabled:!v||!!a.busy,editTip:v===!1?l("config.incomplete"):void 0}}function Js({config:n,editor:s}){const e=R(),t=J[q()],[a,r]=h.useState("all"),[l,p]=h.useState(null),[c,d]=h.useState(null);V(n.generation_id,()=>{p(null),d(null)});const i=h.useMemo(()=>ne(l?.diagnostics??n.diagnostics,n.sources,t,e),[l,n.diagnostics,n.sources,t,e]),f=m=>i.reduce((S,N)=>S+(N.level===m?N.count:0),0),b=f("error"),v=f("warning"),x=a==="all"?i:i.filter(m=>m.level===a),k=i.find(m=>m.id===c)??null,C=ue(n.sources),j=ge(n.sources,C);return{level:a,setLevel:r,selected:c,setSelected:d,shown:x,cur:k,validate:()=>{j&&s.validate({sources:j,mode:"full"}).then(m=>{m&&(p(m),d(null))})},summaryTone:b?"err":v?"warn":"ok",summary:b?e("config.failed",{errors:e("config.errors",{n:b}),warnings:e("config.warnings",{n:v})}):v?e("config.passedWarnings",{n:v}):e("config.passed"),lastRun:l?e("config.lastRun",{time:Te(l.validated_at,t)}):e("config.acceptedDiagnostics",{generation:n.generation_id}),validating:s.busy==="validate",blocked:!!s.busy||!j,tip:j?void 0:e("config.incomplete"),levels:[["all",e("config.levelAll",{n:b+v+f("info")})],["error",e("config.levelErrors",{n:b})],["warning",e("config.levelWarnings",{n:v})],["info",e("config.levelInfo",{n:f("info")})]]}}function Qs({config:n,editor:s,canWrite:e,canValidate:t,open:a}){const r=R(),l=q(),p=J[l],c=h.useMemo(()=>As(n.sources,l,r),[n,l,r]),d=ue(n.sources),[i,f]=h.useState(null),[b,v]=h.useState(null),x=i!==null&&i.text!==i.section.source.content.slice(i.section.block.from,i.section.block.to),C=s.error instanceof ee&&s.error.status===412&&!!i&&s.errorSource===i.section.source.id?c.find(u=>u.id===i.section.id&&u.source&&u.block&&u.source.content_sha256!==i.section.source.content_sha256):void 0;V(C??null,u=>{u?.source&&u.block&&f(z=>z&&{...z,section:{...u,source:u.source,block:u.block}})});const j=le(x,()=>{f(null),v(null)}),{clear:g}=j;h.useEffect(()=>s.cancel,[s.cancel,j.revision]);const m=h.useMemo(()=>i?Rs(i.section.source.content,i.section.block,i.text):null,[i]),S=i?.section.source.id,N=ge(n.sources,d,S&&m!==null?{id:S,content:m}:void 0);Ae(t&&m!==null?N:null,v);const E=(s.errorSource===S?s.diagnostics:null)??b??n.diagnostics,w=h.useMemo(()=>E.filter(u=>u.source_id===S),[E,S]),P=i?.section.id,A=h.useMemo(()=>({own:w,sectionId:P}),[w,P]),[y,M]=h.useState([]);V(A,u=>M(i?Ls(u.own,i.section.source.id,i.section.block,i.text):[]));const K=h.useMemo(()=>Le(n.sources,S&&m!==null?{id:S,content:m}:void 0),[S,m,n]),B=()=>{s.cancel(),g(),f(null),v(null)},D=(u,z)=>{v(z),_(u?"positive":"negative",u?r("config.valid"):r("config.invalid",{n:z.filter(X=>X.level==="error").length}))},F=async()=>{if(!i||!N||m===null||s.busy)return;const u=await s.validate({sources:N,mode:"full"});u&&D(u.valid,u.diagnostics)},$=async()=>{if(!i||m===null||s.busy||!x)return;const u=await s.apply(i.section.source,m);if(u){if(u.diagnostics){D(!1,u.diagnostics);return}_("positive",r("config.saved",{path:G(i.section.source,p,r).label})),g(),f(null),v(null)}};return{cards:(i&&!c.some(u=>u.id===i.section.id)?[...c,i.section]:c).map(u=>({...u,editing:i?.section.id===u.id,canEdit:e&&!!u.source?.writable&&!!u.block&&d(u.source)===!0,editDisabled:x||!!s.busy,note:u.note??(u.source&&u.block&&d(u.source)===!1?r("config.incomplete"):null),muted:!u.block,manual:u.source&&u.source.content!==void 0?()=>a(u.source.id,u.block?u.block.line+1:null):null,edit:()=>{x||s.busy||!e||!u.source?.writable||!u.block||d(u.source)!==!0||(v(null),f({section:{...u,source:u.source,block:u.block},text:u.source.content.slice(u.block.from,u.block.to)}))}})),text:i?.text??"",change:u=>f(z=>z?{...z,text:u}:null),marks:y,diagnostics:ne(w,n.sources,p,r),outbounds:()=>K,dirty:x,busy:!!s.busy,saving:s.busy==="save",validating:s.busy==="validate",canValidate:t&&!!N,validate:F,save:$,cancel:B}}function Xs({sources:n,contentOffered:s,refetch:e,open:t}){const a=R(),r=n.find(m=>m.kind==="main"),l=h.useMemo(()=>s&&r?.content!==void 0?tn(r.content):null,[s,r]),p=h.useMemo(()=>on(l??[]),[l]),[c,d]=h.useState(null),[i,f]=h.useState(null),{busy:b,create:v}=rn(e),x=c?.text??"",k=p.find(m=>m.pattern===c?.pattern)??null,C=k?k.prefix+x+k.suffix:x,j=x?k?an(x,k):ln(x):null,g=async m=>{if(!(!x||j||b))try{const S=await v(C);if(!S)return;m(),_("positive",a("config.newSourceCreated",{path:C})),S.id&&t(S.id)}catch(S){f(N=>({id:(N?.id??0)+1,text:Ee(S,a)}))}};return{isOpen:c!==null,show:()=>{f(null),d({text:p.length?"":dn(l??[]),pattern:p[0]?.pattern??""})},hide:()=>d(null),choices:p,choice:k,setChoice:m=>d(S=>S&&{...S,pattern:m}),text:x,setText:m=>d(S=>S&&{...S,text:m}),error:j?a(j):void 0,unmatched:!!x&&!j&&l!==null&&!cn(l,C),problem:i,busy:b,canSubmit:!!x&&!j&&!b,submit:g}}function mt(n){const s=R(),{error:e,reload:t,loading:a,ready:r,metadata:l,redacted:p,tabs:c,tab:d,setTab:i,selectedId:f,select:b,sourceProps:v,newSourceProps:x,wizardProps:k,validateProps:C,modulesProps:j,sourceModel:g,sourceOptions:m,exportSource:S,summaryTone:N,summaryText:E}=Us(n),w={modules:j&&o.jsx(Zs,{...j}),setup:k&&o.jsx(Bs,{...k}),source:o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(de,{side:!0,label:s("config.source"),value:f,onChange:b,items:m}),g&&o.jsxs(o.Fragment,{children:[o.jsx(pe,{children:g.kind}),o.jsx(L,{small:!0,tone:g.tone,children:g.editable}),o.jsx("span",{className:"rp-label",children:g.facts})]}),(x||g?.hasContent)&&o.jsx("span",{className:"rp-grow"}),x&&o.jsx(Ys,{...x}),g?.hasContent&&o.jsx(o.Fragment,{children:o.jsxs(T,{onPress:S,children:[o.jsx(un,{}),s("config.export")]})})]}),g?.hasContent&&o.jsx("span",{className:"rp-label",children:s("config.exportWarning")}),v&&o.jsx(et,{...v},g.id)]}),validate:C&&o.jsx(nt,{...C})};return o.jsxs("div",{className:"rp-page",children:[o.jsx(pn,{error:e,onRetry:t}),a&&o.jsx(fn,{}),r&&o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(gn,{row:!0,items:l}),o.jsx(L,{small:!0,tone:N,children:E}),p&&o.jsx(L,{small:!0,tone:"muted",children:s("config.redacted")})]}),r&&o.jsx(mn,{label:s("nav.config"),value:d,onChange:i,items:c.map(P=>({...P,content:w[P.id]}))})]})}function Ys(n){const s=R(),e=Xs(n);return o.jsxs(o.Fragment,{children:[o.jsxs(T,{onPress:e.show,children:[o.jsx(Cn,{}),s("config.newSource")]}),o.jsxs(xn,{title:s("config.newSourceTitle"),narrow:!0,isOpen:e.isOpen,onOpenChange:t=>{t||e.hide()},footer:t=>o.jsxs(o.Fragment,{children:[o.jsx(T,{onPress:t,children:s("ui.cancel")}),o.jsx(T,{accent:!0,isDisabled:!e.canSubmit,isPending:e.busy,onPress:()=>void e.submit(t),children:s("config.newSourceCreate")})]}),children:[e.problem&&o.jsx(be,{takeFocus:!0,children:e.problem.text},e.problem.id),o.jsxs("div",{className:"rp-list",children:[o.jsx("span",{className:"rp-label",children:s(e.choice?"config.newSourceNameHelp":"config.newSourceHelp")}),e.choices.length>1&&o.jsx(de,{label:s("config.newSourcePattern"),items:e.choices.map(t=>({id:t.pattern,label:t.pattern})),value:e.choice?.pattern??"",onChange:e.setChoice,isDisabled:e.busy}),e.choice?o.jsx(O,{isDisabled:e.busy,label:s("config.newSourceName"),value:e.text,prefix:e.choice.prefix,suffix:e.choice.suffix,placeholder:"extra",spellCheck:!1,error:e.error,onChange:e.setText}):o.jsx(O,{isDisabled:e.busy,label:s("config.newSourcePath"),value:e.text,placeholder:"config.d/extra.dae",spellCheck:!1,error:e.error,onChange:e.setText}),e.unmatched&&o.jsx(be,{tone:"informative",children:s("config.newSourceUnmatched")})]})]})]})}function Zs(n){const s=R(),e=Qs(n);return o.jsx("div",{className:"rp-page",children:e.cards.map(t=>o.jsxs(ce,{"aria-label":t.kind,children:[o.jsxs("div",{className:"rp-row",children:[o.jsxs("span",{className:"rp-cluster",children:[o.jsx("h3",{className:"rp-h3 rp-code",children:t.kind}),o.jsx("span",{className:"rp-label rp-code",children:t.range}),t.editing&&e.dirty&&o.jsx(pe,{tone:"warn",children:s("config.unsaved")})]}),o.jsxs("span",{className:"rp-cluster",children:[t.href&&o.jsx(yn,{appearance:"button",href:t.href,children:s("config.moduleOpen")}),t.canEdit&&!t.editing&&o.jsx(T,{isDisabled:t.editDisabled,onPress:t.edit,children:s("config.edit")}),t.manual&&!t.editing&&o.jsx(T,{quiet:!0,tip:s("config.moduleManualTip"),onPress:t.manual,children:s("config.moduleManual")})]})]}),o.jsx(L,{small:!0,tone:t.muted?"muted":"info",children:t.summary}),t.note&&o.jsx(L,{small:!0,tone:"muted",children:t.note}),t.editing&&o.jsxs(o.Fragment,{children:[o.jsx(fe,{label:t.range,value:e.text,onChange:e.change,readOnly:e.busy,marks:e.marks,outbounds:e.outbounds,onSave:e.dirty&&!e.busy?()=>void e.save():void 0}),e.diagnostics.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":s("config.diagnostics"),children:e.diagnostics.map(a=>o.jsx("div",{role:"listitem",children:o.jsx(L,{small:!0,tone:a.tone,children:a.detail})},a.id))}),o.jsxs("div",{className:"rp-cluster",children:[e.canValidate&&o.jsx(T,{isPending:e.validating,isDisabled:e.busy,onPress:()=>void e.validate(),children:s("config.validate")}),o.jsx(T,{accent:!0,isPending:e.saving,isDisabled:e.busy||!e.dirty,onPress:()=>void e.save(),children:s("config.save")}),o.jsx(T,{isDisabled:e.busy,onPress:e.cancel,children:s("ui.cancel")})]})]})]},t.id))})}function et(n){const{canValidate:s,canWrite:e,contentOffered:t}=n,a=R(),{editing:r,shown:l,marks:p,text:c,outbounds:d,focus:i,dirty:f,validate:b,save:v,edit:x,cancel:k,change:C,view:j,busy:g,validating:m,saving:S,saveTip:N,validateDisabled:E,validateTip:w,editDisabled:P,editTip:A}=qs(n);return o.jsxs(ce,{children:[o.jsxs("div",{className:"rp-row",children:[o.jsxs("span",{className:"rp-cluster",children:[o.jsx("h3",{className:"rp-h3 rp-code",children:j.label}),f&&o.jsxs(o.Fragment,{children:[o.jsx(pe,{tone:"warn",children:a("config.unsaved")}),o.jsx("span",{className:"rp-label",children:a("config.unsavedHint")})]})]}),o.jsxs("span",{className:"rp-cluster",children:[s&&o.jsx(T,{isPending:m,isDisabled:E,tip:w,onPress:()=>void b(),children:a("config.validate")}),e&&!r&&o.jsx(T,{isDisabled:P,tip:A,onPress:x,children:a("config.edit")}),r&&o.jsxs(o.Fragment,{children:[o.jsx(T,{isDisabled:g,onPress:k,children:a("ui.cancel")}),o.jsx(T,{accent:!0,isPending:S,isDisabled:g||!f,tip:N,onPress:()=>void v(),children:a("config.save")})]})]})]}),l.length>0&&o.jsx("div",{className:"rp-list rp-config-diagnostics",role:"list","aria-label":a("config.diagnostics"),children:l.map((y,M)=>o.jsxs("div",{className:"rp-cluster",role:"listitem",children:[o.jsx(L,{small:!0,tone:y.tone,children:y.detail}),o.jsx(T,{small:!0,quiet:!0,label:a("config.openSourceAt",{where:y.where}),onPress:()=>n.open(y.sourceId,y.line),children:a("config.openSource")})]},M))}),j.hasContent?o.jsx(fe,{label:j.label,value:c,readOnly:!r||g,onChange:r?C:void 0,marks:p,focusLine:i,outbounds:d,onSave:r&&f&&!g?()=>void v():void 0}):o.jsx(wn,{children:a(t?"config.contentWithheld":"config.contentHidden")}),o.jsx("span",{className:"rp-label",children:a(e?"config.editNote":"config.readNote")})]})}function nt(n){const{canValidate:s,open:e}=n,t=R(),{level:a,setLevel:r,selected:l,setSelected:p,shown:c,cur:d,validate:i,summaryTone:f,summary:b,lastRun:v,validating:x,blocked:k,tip:C,levels:j}=Js(n);return o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"rp-toolbar",children:[o.jsx(L,{small:!0,tone:f,children:b}),o.jsx("span",{className:"rp-label",children:v}),o.jsx("span",{className:"rp-grow"}),s&&o.jsxs(T,{isPending:x,isDisabled:k,tip:C,onPress:i,children:[o.jsx(hn,{className:"rp-spin-on-press"}),t("config.revalidate")]})]}),o.jsx("span",{className:"rp-label",children:t("config.validateNote")}),o.jsx(bn,{label:t("config.level"),value:a,onChange:r,items:j}),o.jsx(kn,{label:t("config.diagnostics"),rowDetail:!0,rows:c,height:360,selected:l,onSelect:p,empty:t("config.noDiagnostics"),cols:[{id:"level",label:t("config.level"),minWidth:96,grow:0,render:g=>o.jsx(L,{small:!0,tone:g.tone,children:g.levelText})},{id:"where",label:t("config.where"),minWidth:150,grow:0,render:g=>o.jsx("span",{className:"rp-code",children:g.where})},{id:"message",label:t("config.message"),minWidth:240,grow:2,isRowHeader:!0,render:g=>o.jsx(vn,{children:g.message})},{id:"code",label:t("config.code"),minWidth:140,drop:1,render:g=>o.jsx(Fe,{text:g.code})}]}),d&&o.jsxs("div",{className:"rp-cluster rp-config-diagnostics",children:[o.jsx(L,{small:!0,tone:d.tone,children:d.detail}),o.jsx(T,{label:t("config.openSourceAt",{where:d.where}),onPress:()=>e(d.sourceId,d.line),children:t("config.openSource")})]})]})}export{mt as Config};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Connections-DAjj-jeW.js b/luci-app-honk/root/etc/honk/dashboard/assets/Connections-DAjj-jeW.js
deleted file mode 100644
index b133774b9..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Connections-DAjj-jeW.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import{j as s,r as v}from"./vendor-react-Bf71BWbF.js";import{aB as sn,aC as on,aD as ue,aE as le,u as J,as as Be,X as he,_ as fe,ag as z,aF as Z,aG as an,aw as Ie,aH as ln,ax as pe,E as xe,W as se,aI as rn,aJ as cn,O as ie,Q as oe,S as dn,V as ge,aK as we,aL as Ee,aM as me,ah as un,aN as pn,aO as mn,aP as bn,al as je,aQ as hn,aR as Ve,ay as be,av as te,M as fn,I as _e,aS as We,aT as ae,B as O,aU as xn,aV as gn,aW as Ue,aX as wn,$ as He,a1 as Q,a5 as vn,a3 as yn,aY as jn,aZ as _n,a_ as kn,a$ as Nn,b0 as K,b1 as ke,b2 as Cn,N as Mn,a0 as Ln,b3 as Sn,R as Tn,a2 as An,b4 as Pn,b5 as Qe,b6 as Rn,a as Ne,b7 as Dn,b8 as Fn,A as On,T as Ce,b9 as de,ba as Bn,bb as In,at as En,au as Me,bc as Vn}from"./index-zQjLFfuj.js";import{F as Wn}from"./FactStrip-vcLr7nBw.js";import{B as Un,r as Hn}from"./ranked-C_Wt6A1w.js";import{u as Qn,C as Kn,s as Le,a as Gn,p as Se}from"./layout-B3T-zLsm.js";import{D as Jn}from"./Table-DLlwyNFJ.js";import{T as $n}from"./TimeCell-DxlzlVpw.js";import{t as Y,r as Ke,w as Te,a as Xn}from"./link-CaqmdEp1.js";import{c as Ae,d as Yn,e as Zn}from"./files-BxEOxSF8.js";import{D as qn}from"./DaeCode-B4MDdwFy.js";import{u as zn}from"./outbounds-CM0Hhk3q.js";import{u as et}from"./flows-Bv2rvXJX.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";const H=64,nt=22,X=8,tt=28;function st({label:n,series:t,fmt:e,onSelect:l,regions:c,height:i=260}){const o=sn(),[a,r]=on(),{ref:p,tip:g,show:m,hide:h}=Qn(),w=Math.max(1,...t.flatMap(b=>b.points.flatMap(N=>[N.x,N.y]))),{end:u,ticks:R}=Gn(w),M=Math.max((r??0)-H-tt,1),_=i-X-nt,j=b=>H+Le(b,u)*M,y=b=>X+(1-Le(b,u))*_,D=new Map,k=t.flatMap(b=>b.points.map(N=>{const T=j(N.x),A=y(N.y),F=T+","+A,L=D.get(F)??0;return D.set(F,L+1),{point:N,color:b.color,cx:T,cy:A,nth:L,spot:F}})).map(b=>({...b,twins:D.get(b.spot)}));return s.jsx("div",{className:"rp-scatter",ref:a,children:s.jsxs("div",{className:"rp-chart-hover",ref:p,onPointerLeave:h,children:[r!==null&&s.jsxs("svg",{width:r,height:i,role:"img","aria-label":n,"aria-describedby":o,children:[R.map(b=>s.jsxs("g",{children:[s.jsx("line",{className:"grid",x1:j(b),x2:j(b),y1:X,y2:X+_}),s.jsx("line",{className:"grid",x1:H,x2:H+M,y1:y(b),y2:y(b)}),s.jsx("text",{className:"tick",x:j(b),y:i-6,textAnchor:"middle",children:e(b)}),s.jsx("text",{className:"tick",x:H-8,y:y(b)+4,textAnchor:"end",children:e(b)})]},b)),c&&s.jsxs("g",{className:"diagonal",children:[s.jsx("line",{x1:j(0),y1:y(0),x2:j(u),y2:y(u)}),s.jsx("text",{x:H+8,y:X+14,children:c.above}),s.jsx("text",{x:H+M-8,y:X+_-8,textAnchor:"end",children:c.below})]}),k.map(({point:b,color:N,cx:T,cy:A,nth:F,twins:L})=>{const P=2*Math.PI*F/L,S=L>1?6:0;return s.jsx("circle",{className:l?"pick":void 0,cx:T+S*Math.cos(P),cy:A+S*Math.sin(P),r:5,fill:N,onClick:l?()=>l(b.id):void 0,onPointerMove:E=>m(E,[b.name,b.detail])},b.id)})]}),s.jsx(Kn,{tip:g})]})})}function ot({series:n}){return s.jsx("div",{className:"rp-legend",children:n.map(t=>s.jsx(ue,{swatch:t.color,label:t.label,value:String(t.points.length)},t.id))})}function at(n){const t=new Map;let e=0;for(const o of n){if(o.upload_bytes===null||o.download_bytes===null){e++;continue}const a={id:o.id,up:Number(o.upload_bytes),down:Number(o.download_bytes),name:o.domain||o.dst||o.id},r=t.get(o.outbound);r?r.push(a):t.set(o.outbound,[a])}const l=[...t].map(([o,a])=>({outbound:o,points:a})).sort((o,a)=>le(o.outbound??"",a.outbound??""));let c,i=-1n;for(const o of n){if(o.upload_bytes===null||o.download_bytes===null)continue;const a=BigInt(o.upload_bytes)+BigInt(o.download_bytes);a>i&&(i=a,c={id:o.id,up:Number(o.upload_bytes),down:Number(o.download_bytes),name:o.domain||o.dst||o.id,outbound:o.outbound})}return{series:l,unknown:e,heaviest:c,placed:n.length-e}}const Pe=[0,2,3,1,4,5,6,7],lt=v.memo(function({records:t,outbounds:e,latency:l,latencyError:c,retryLatency:i,truncated:o,onSelect:a}){const r=J(),p=Be(),g=he[fe()],m=v.useCallback(M=>z(M,g),[g]),h=v.useMemo(()=>at(t),[t]),w=v.useMemo(()=>{const M=e.filter(j=>j!=="block"),_=j=>j==="block"?p.negative:p.cat[Pe[Math.max(0,M.indexOf(j))%Pe.length]];return h.series.map(j=>({id:j.outbound??"",label:Z(j.outbound,r),color:_(j.outbound),points:j.points.map(y=>({id:y.id,x:y.up,y:y.down,name:y.name,detail:r("conn.chart.point",{down:m(y.down),up:m(y.up)})}))}))},[h,e,p,r,m]),u=h.heaviest?[{label:r("conn.chart.busiest"),icon:s.jsx(an,{}),tint:"c3",value:h.heaviest.name,caption:Z(h.heaviest.outbound,r)},{label:r("conn.chart.down"),value:m(h.heaviest.down),icon:s.jsx(Ie,{}),tint:"c1"},{label:r("conn.chart.up"),value:m(h.heaviest.up),icon:s.jsx(ln,{}),tint:"c4"}]:[],R=h.unknown?r("conn.chart.sampleUnknown",{n:t.length,unknown:h.unknown}):r("conn.chart.sample",{n:t.length});return s.jsxs("div",{className:"rp-chart-page",children:[s.jsx(Wn,{facts:u,lead:!0}),s.jsxs(pe,{title:r("conn.chart.title"),note:R,children:[o&&s.jsx("p",{className:"rp-note",children:r("conn.truncated")}),h.placed>0&&s.jsxs(s.Fragment,{children:[s.jsx(st,{label:r("conn.chart.title"),series:w,fmt:m,onSelect:a,regions:{above:r("conn.chart.moreDown"),below:r("conn.chart.moreUp")}}),s.jsx(ot,{series:w}),s.jsx("p",{className:"rp-note",children:r("conn.chart.hint")})]})]}),l?s.jsx(it,{latency:l}):c&&s.jsx(pe,{title:r("conn.latency.title"),children:s.jsx(xe,{error:c,onRetry:i})})]})});function it({latency:n}){const t=J(),e=Be(),l=o=>rn(o,t),c=he[fe()],i=o=>!n.chains||o?e.cat[0]:e.muted;return s.jsx(pe,{title:t("conn.latency.title"),note:t("conn.latency.sample",{n:n.samples.length,missing:n.missing}),children:n.samples.length?s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"rp-note",children:t("conn.latency.percentiles",{p50:l(n.p50),p90:l(n.p90)})}),n.weightedP50!==null&&s.jsx("p",{className:"rp-note",children:n.unplaced?t("conn.latency.weightedUnplaced",{p50:l(n.weightedP50),n:n.unplaced}):t("conn.latency.weighted",{p50:l(n.weightedP50)})}),s.jsx(Un,{label:t("conn.latency.title"),points:n.samples.map(o=>({id:o.node,value:o.value,color:i(o.connections>0),lines:[o.name,l(o.value),...o.connections?[t("conn.chart.sample",{n:o.connections})]:[]]})),fmt:l}),n.chains&&s.jsxs("div",{className:"rp-legend",children:[s.jsx(ue,{swatch:i(!0),label:t("conn.latency.inUse"),value:se(n.used,c)}),s.jsx(ue,{swatch:i(!1),label:t("conn.latency.others"),value:se(n.samples.length-n.used,c)})]}),s.jsx("p",{className:"rp-note",children:t("conn.latency.hint")})]}):s.jsx("p",{className:"rp-note",children:t("conn.latency.pending")})})}const Re={userspace:"conn.observed.userspace",ebpf:"conn.observed.ebpf",mixed:"conn.observed.mixed"};function rt(n,t){return[["ui.device",n.src??"—"],["conn.f.dst",n.dst??"—"],["ui.domain",n.domain??"—"],["conn.f.ingress",Te(n.ingress)],["conn.f.domainSource",Te(n.domain_source)],["ui.process",n.pname??"—"],["conn.f.observedBy",Re[n.observed_by]?{key:Re[n.observed_by]}:n.observed_by],["ui.upload",z(n.upload_bytes,t)],["ui.download",z(n.download_bytes,t)],["conn.f.uploadRate",me(n.upload_bytes_per_second,t)],["conn.f.downloadRate",me(n.download_bytes_per_second,t)],["conn.f.started",un(n.started_at,t)]]}const G=[{id:"dst",label:"ui.target",minWidth:200,sortable:!0},{id:"src",label:"ui.device",minWidth:128,sortable:!0,drop:5},{id:"node",label:"conn.node",minWidth:120,drop:3},{id:"rule",label:"conn.rule",minWidth:220,drop:2},{id:"state",label:"ui.state",minWidth:88,sortable:!0,drop:7},{id:"down",label:"ui.download",minWidth:96,align:"end",sortable:!0,drop:4},{id:"downRate",label:"conn.f.downloadRate",minWidth:128,align:"end",sortable:!0,drop:1},{id:"age",label:"ui.started",minWidth:132,align:"end",sortable:!0,drop:6}],De=cn.connectionsView;function Fe(n){const t={hidden:[],sort:null,group:"source"};try{const e=JSON.parse(n??"null");if(!e||typeof e!="object")return t;const l=Array.isArray(e.hidden)?e.hidden.map(o=>o==="chain"?"node":o):[],c=G.filter(o=>l.includes(o.id)).map(o=>o.id),i=e.sort;return{hidden:c.length===G.length?[]:c,sort:i&&G.some(o=>o.sortable&&o.id===i.column)&&["ascending","descending"].includes(i.direction)?{column:i.column,direction:i.direction}:null,group:e.group==="none"||e.group==="outbound"?e.group:"source"}}catch{return t}}function ct(n,t,e){return n.map(l=>({item:l,key:t(l)})).sort((l,c)=>e(l.key,c.key)).map(l=>l.item)}function dt(n,t,e){let l=n;if(t.sort){const{column:i,direction:o}=t.sort;l=ct(n,r=>{switch(i){case"dst":return r.domain||r.dst;case"src":return r.src;case"state":return ge(we,r.state,e);case"down":return je(r.download_bytes);case"downRate":return je(r.download_bytes_per_second);case"age":return r.started_at?Date.parse(r.started_at):null;default:return null}},(r,p)=>{if(r==null)return p==null?0:1;if(p==null)return-1;const g=typeof r=="string"&&typeof p=="string"?le(r,p):r
p?1:0;return o==="descending"?-g:g})}if(t.group==="none")return l.map(i=>({id:i.id,connection:i}));const c=new Map;for(const i of l){const o=t.group==="source"?ie(i.src??void 0)??i.src??"—":Z(i.outbound,e),a=c.get(o);a?a.push(i):c.set(o,[i])}return[...c].map(([i,o],a)=>({id:a,group:i,children:o,active:o.filter(r=>r.state==="active").length,download:pn(...o.map(r=>r.download_bytes))}))}const Oe=new WeakMap;function ut(n,t,e,l,c,i){const o=a=>{const r=Oe.get(a);if(r&&r.locale===e&&r.names===l&&r.rulesListed===c&&r.t===i)return r.row;const p={id:a.id,target:a.domain||a.dst||"—",source:a.src??"—",node:bn(a,i,l),path:mn(a,i,l),rule:{expression:a.rule_expression,href:Ke(a.rule_id,c)},recomputed:a.rule_source==="recomputed"?i("conn.recomputed"):null,state:ge(we,a.state,i),download:z(a.download_bytes,e),downloadRate:me(a.download_bytes_per_second,e),startedAt:a.started_at};return Oe.set(a,{locale:e,names:l,rulesListed:c,t:i,row:p}),p};return dt(n,t,i).map(a=>"connection"in a?{id:a.id,connection:o(a.connection)}:{id:a.id,group:a.group,children:a.children.map(o),label:i("conn.groupCount",{name:a.group,n:a.children.length}),totals:{down:z(a.download,e),state:i("conn.activeCount",{n:a.active})}})}function pt(n,t,e,l,c,i){const o=a=>{const r=a.flatMap(p=>p?[p]:[]);return Hn(r,12).top};return{networks:[["all",i("ui.allCount",{n:n.length})],["tcp",i("ui.tcp")],["udp",i("ui.udp")]],outbounds:[{id:"all",label:i("conn.allOutbounds")},...[...new Set(n.flatMap(a=>a.outbound?[a.outbound]:[]))].map(a=>({id:a,label:Z(a,i)}))],picks:[{title:i("ui.device"),value:Y("src",e??""),items:o(n.map(a=>ie(a.src))).map(({key:a,count:r})=>({id:Y("src",a),label:a,desc:se(r,c)}))},{title:i("conn.rule"),value:Y("rule",l),items:o(n.map(a=>a.rule_expression)).map(({key:a,count:r})=>({id:Y("rule",a),label:a,desc:se(r,c)}))}],visibility:t&&t.visibility!=="full"?i(t.visibility==="none"?"conn.visibilityNone":"conn.visibilityPartial"):null}}function mt(n,t,e){const[l,c]=n.picks,i=(o,a,r,p)=>({filter:o,label:a,sections:[{title:a,items:r,value:p}]});return{active:[t.network!=="all",t.out!=="all",!!t.src,t.rule!=="all"].filter(Boolean).length,submenus:[i("network",e("ui.network"),n.networks.map(([o,a])=>({id:o,label:a})),t.network),i("out",e("ui.outbound"),n.outbounds,t.out),i("src",l.title,[{id:Y("src",""),label:e("conn.allDevices")},...l.items],l.value),i("rule",c.title,[{id:Y("rule","all"),label:e("conn.allRules")},...c.items],c.value)]}}function bt(n,t,e,l,c){return n?{id:n.id,title:n.domain||n.dst||n.id,tone:n.state==="blocked"||n.state==="failed"?"err":n.state==="active"?"ok":"info",status:e("ui.aside",{text:ge(we,n.state,e),note:n.network.toUpperCase()}),chain:dn(n,e,l),outbound:Z(n.outbound,e),rule:{expression:n.rule_expression,href:Ke(n.rule_id,c)},fields:rt(n,t).map(([i,o])=>[e(i),typeof o=="string"?o:e(o.key,o.params)]),flowQuery:oe("",{tab:"flows",...n.flow_id?{id:n.flow_id}:{connection_id:n.id}}),source:n.src?ie(n.src)??n.src:null,closable:n.state==="active"||n.state==="dialing"||n.state==="routing"}:null}function ht(n,t){return[Ae(["id","target","domain","source","network","state","outbound","chain","rule","upload_bytes","download_bytes","started_at"]),...n.map(e=>Ae([e.id,e.dst,e.domain,e.src,e.network,e.state,e.outbound,Ee(e.chain,t).join(" > "),e.rule_expression,e.upload_bytes,e.download_bytes,e.started_at]))].join(`
-`)+`
-`}function ft(n,t){const e=n.map(c=>c.id),l=t.bulkLimit!=null&&e.length>t.bulkLimit;return t.narrowed||t.truncated||l?{ids:e}:{ids:e,query:{type:t.network,src:t.src,all:!0}}}const xt=n=>n.target;function gt({collection:n,view:t,loading:e,selected:l,onSelect:c,selectOnFocus:i,onSort:o}){const a=J(),[r,p]=hn(442),g=v.useMemo(()=>{const w={dst:u=>s.jsx(te,{children:u.target}),src:u=>s.jsx(te,{className:"rp-code",children:u.source}),node:u=>s.jsx(te,{className:"rp-chain",text:u.path??void 0,children:u.node}),rule:u=>s.jsxs("span",{className:"rp-rule",children:[s.jsx(Ve,{...u.rule}),u.recomputed&&s.jsx(be,{children:u.recomputed})]}),state:u=>u.state,down:u=>u.download,downRate:u=>u.downloadRate,age:u=>s.jsx($n,{at:u.startedAt})};return G.filter(u=>!t.hidden.includes(u.id)).map(u=>({...u,label:a(u.label),grow:1,render:w[u.id]}))},[t.hidden,a]),m=v.useMemo(()=>n.map(w=>"connection"in w?w.connection:w),[n]),h=v.useMemo(()=>({grouped:t.group!=="none"}),[t.group]);return s.jsx("div",{ref:r,children:s.jsx(Jn,{label:a("nav.connections"),rowDetail:!0,cols:g,rows:m,height:p,selected:l,onSelect:c,selectOnFocus:i,reveal:!0,empty:a("conn.empty"),loading:e,sort:t.sort&&{column:String(t.sort.column),direction:t.sort.direction},onSort:o,getTextValue:xt,stream:!0,tree:h})})}function wt({dialog:n}){const t=J();return s.jsxs(fn,{title:t("rule.add"),narrow:!0,isOpen:!!n,onOpenChange:e=>{e||n?.close()},footer:()=>s.jsxs(s.Fragment,{children:[s.jsx(O,{onPress:()=>n?.close(),children:t("ui.cancel")}),s.jsx(O,{isDisabled:n?.disabled,isPending:n?.busy,onPress:()=>n?.applyNow(),children:t("rule.addApply")}),s.jsx(O,{accent:!0,isDisabled:n?.disabled||n?.busy,onPress:()=>n?.hold(),children:t("rule.hold")})]}),children:[n?.failure&&s.jsx(_e,{takeFocus:!0,children:n.failure.text},n.failure.id),n&&s.jsxs("div",{className:"rp-list",children:[n.failure?.lines.map((e,l)=>s.jsx("span",{className:"rp-label",children:e},l)),s.jsx(xe,{error:n.loadError,onRetry:n.retry}),s.jsx("span",{className:"rp-label",children:t("rule.holdHelp")}),n.targets&&s.jsx(We,{isDisabled:n.busy,label:t("rule.kind"),value:n.target,onChange:n.setTarget,items:n.targets}),s.jsxs("div",{className:"rp-toolbar top",children:[s.jsx(ae,{isDisabled:n.busy,label:t("ui.outbound"),value:n.outbound,onChange:n.setOutbound,items:n.outbounds}),s.jsx(ae,{isDisabled:n.busy||!n.positions.length,label:t("rule.position"),value:n.before,onChange:n.setBefore,items:n.positions})]}),n.moved&&s.jsx(_e,{tone:"informative",children:t("conn.ruleMoved")}),n.unplaceable&&s.jsx("p",{className:"rp-note",children:t("conn.ruleNoPosition")}),s.jsx(qn,{text:n.preview})]})]})}function vt(n,t){if(!t.some(m=>m.health?.length))return null;const e=[];let l=0;for(const m of t){const h=xn(gn(m.health??[]));h===void 0?l++:e.push({node:m.id,name:m.name,value:h,connections:0})}e.sort((m,h)=>m.value-h.value||le(m.name,h.name));const c=new Map(e.map(m=>[m.node,m])),i=n.some(m=>m.chain?.length);let o=0;for(const m of n){const h=m.chain?.at(-1);if(h===void 0)continue;const w=c.get(h);w?w.connections++:o++}const a=e.reduce((m,h)=>m+h.connections,0);let r=0;const p=e.find(m=>(r+=m.connections)>=Math.max(1,Math.ceil(a/2))),g=e.map(m=>m.value);return{samples:e,chains:i,missing:l,unplaced:o,used:e.filter(m=>m.connections).length,p50:Se(g,50),p90:Se(g,90),weightedP50:a?p.value:null}}function yt(n){const t=c=>c.flatMap(([i,o])=>{const a=wn(i,o);return a?[{kind:i,condition:a}]:[]}),e=n.domain?t([["domain",n.domain],["domainSuffix",n.domain]]):[],l=ie(n.dst);return e.length?e:l?t([["dip",l]]):[]}function jt(n,t,e,l){const c=r=>{const p=t.find(g=>g.id===r.source?.source_id);return!!p?.writable&&Ue(p,r)!==null},i=n.find(r=>r.rule_id===e&&c(r)),o=n.find(c),a=r=>r===n[0]?l("conn.ruleTop"):l("rule.positionBefore",{n:r.index+1});return[...i?[{rule:i,label:l("conn.ruleBeforeMatched")}]:[],...o&&o!==i?[{rule:o,label:a(o)}]:[]].map(({rule:r,label:p})=>({id:r.rule_id,label:p,desc:r.expression}))}function _t(n,t,e){if(!t)return{before:n[0]?.id,moved:!1};const l=n.find(c=>c.id===t.rule.rule_id&&(e===t.generation||c.desc===t.rule.expression));return l?{before:l.id,moved:!1}:{before:n[0]?.id,moved:!0}}function kt(n){const t=J(),e=He().data?.resources,l=Q(e,"rules",{whileLoading:!1})&&Q(e,"config",{whileLoading:!1})&&e?.config.writable===!0,[c,i]=v.useState(null),[o,a]=v.useState(null),r=!!c,p=et(r),g=vn(r),m=Q(e,"groups",{whileLoading:!1}),h=yn(r&&m),w=()=>{p.refetch(),g.refetch(),m&&h.refetch()},u=jn(),R=g.data?.sources??[],M=jt(p.data?.rules??[],R,c?.matched??null,t),_=_n(h.data??[]),j=!m||!!h.data,y=c?.outbound||_.find(f=>f.id===c?.current)?.id||(j?_[0].id:""),D=p.data?.generation_id,V=f=>{const C=p.data?.rules.find(W=>W.rule_id===f);return C&&D?{generation:D,rule:C}:null},{before:k,moved:b}=_t(M,c?.pin??null,D),N=c&&!c.pin?V(k):null;N&&i({...c,pin:N});const T=c?.targets[c.target],A=f=>{c&&!u.busy&&i({...c,...f})},F=()=>{u.busy&&(u.cancel(),w()),i(null),a(null)},L=()=>{K("negative",t("rule.stale")),w()},P=()=>{const f=p.data?.rules.find(W=>W.rule_id===k),C=R.find(W=>W.id===f?.source?.source_id);return!T||!f||!C||!Ue(C,f)||p.data?.generation_id!==g.data?.generation_id?(L(),null):(b&&i({...c,pin:V(k)}),{condition:T.condition,outbound:y,must:!1,before:f,sourceId:C.id})},S=()=>{const f=P();f&&(Nn.add(f),K("positive",t("rule.held")),F())},E=async()=>{const f=P();if(!f)return;a(null);const C=await u.apply([{...f,id:0}]);if(C){if(!C.written){a({id:Date.now(),...C.failure});return}K(C.failure?"negative":"positive",C.failure?C.failure.text:t("rule.added")),i(null)}},B=n?yt(n):[];return{canAdd:l&&B.length>0,canShow:Q(e,"rules",{whileLoading:!1})&&!!n?.rule_id,openAdd:()=>{n&&i({targets:B,matched:n.rule_id,current:n.outbound,target:0,outbound:"",pin:null})},dialog:c&&{targets:c.targets.length>1?c.targets.map((f,C)=>[String(C),t(`rule.kind.${f.kind}`)]):null,target:String(c.target),setTarget:f=>A({target:Number(f)}),outbounds:_,outbound:y,setOutbound:f=>A({outbound:f}),positions:M,before:k??"",setBefore:f=>A({pin:V(f)}),preview:T?y?kn(T.condition,y):T.condition:"",busy:u.busy,loadError:p.error??g.error??h.error,retry:w,moved:b,unplaceable:!!p.data&&!!g.data&&!M.length,disabled:!T||!k||!j,failure:o,hold:S,applyNow:()=>void E(),close:F}}}const Ge=["traffic","list"],Je=n=>["id","src","network","out","rule","q"].some(t=>new URLSearchParams(n).has(t))?"list":"traffic",q=(n,t)=>oe(n,Je(n)==="list"?{tab:Qe(n,Ge,"list"),...t}:t);function Nt({go:n,query:t}){const e=J(),l=he[fe()],[c,i]=v.useState(()=>{try{return Fe(localStorage.getItem(De))}catch{return Fe(null)}}),o=ke(Fn),a=ke(Dn),r=d=>{const x={...c,...d};i(x);try{localStorage.setItem(De,JSON.stringify(x))}catch{}},p=v.useMemo(()=>new URLSearchParams(t),[t]),[g,m]=v.useState(p.get("q")??""),h=p.get("network")??"all",w=p.get("out")??"all",u=p.get("rule")??"all",R=(d,x)=>n("connections",q(t,{[d]:x==="all"?null:x})),M=p.get("id"),[_,j]=v.useState(null);Cn(p.get("q"),d=>m(d??""));const y=v.useRef(t);v.useEffect(()=>{y.current=t});const D=d=>n("connections",q(y.current,{id:d})),V=v.useDeferredValue(g),k=Mn(p.get("src")??""),b=Ln(k),N=He(),T=N.data?.resources.connections.can_close===!0,A=Q(N.data?.resources,"rules",{whileLoading:!1}),F=Q(N.data?.resources,"flows",{whileLoading:!1}),L=zn(),P=Sn(b.refetch),S=v.useMemo(()=>Tn(b.data),[b.data]),E=Q(N.data?.resources,"nodes",{whileLoading:!1}),B=An(E),f=v.useMemo(()=>E&&B.data?vt(S,B.data):null,[E,B.data,S]),C=E&&!B.data?B.error:null,W=v.useMemo(()=>[...new Set(S.map(d=>d.outbound))].sort((d,x)=>le(d??"",x??"")),[S]),ee=V.trim().toLowerCase(),$=v.useMemo(()=>S.filter(d=>(h==="all"||d.network===h)&&(w==="all"||d.outbound===w)&&(u==="all"||d.rule_expression===u)&&(!ee||[d.dst,d.domain,d.src,d.pname,Z(d.outbound,e),Ee(d.chain,L).join(" "),d.rule_expression].join(" ").toLowerCase().includes(ee))),[S,h,w,u,ee,L,e]),U=M?S.find(d=>d.id===M):void 0,$e=kt(U),ve=v.useMemo(()=>pt(S,b.data,k,u,l,e),[S,b.data,k,u,l,e]),Xe=v.useMemo(()=>bt(U,l,e,L,A),[U,l,e,L,A]),I={...ve,detail:Xe},Ye=v.useMemo(()=>ut($,c,l,L,A,e),[$,c,l,L,A,e]),Ze=async()=>{if(!I.detail)return;const{id:d}=I.detail;try{if(!await P.close(d))return;new URLSearchParams(y.current).get("id")===d&&D(null),K("positive",e("conn.closed",{name:I.detail.title}))}catch(x){x instanceof On&&x.code==="state_conflict"?K("negative",e("conn.notClosable")):K("negative",e("conn.closeFailed"),{detail:Ne(x,e)})}},qe=async()=>{if(_)try{const d=await P.closeAll(_);if(!d)return;D(null),K(Rn(d),e("conn.closedAll",{closed:d.closed,skipped:d.skipped}))}catch(d){return e("ui.valuePair",{label:e("conn.closeFailed"),value:Ne(d,e)})}},re=d=>{const x=Xn(String(d),["src","rule"]);x?.kind==="src"?(m(""),n("connections",q(t,{src:!x.value||k===x.value?null:x.value,q:null}))):x?.kind==="rule"&&R("rule",u===x.value?"all":x.value)},ye=mt(ve,{network:h,out:w,src:k,rule:u},e),ze={network:d=>R("network",d),out:d=>R("out",d),src:re,rule:re},en={active:ye.active,submenus:ye.submenus.map(({filter:d,...x})=>({...x,sections:x.sections.map(ne=>({...ne,onChange:ze[d]}))}))},ce=Je(t),nn=v.useCallback(d=>n("connections",oe(t,{tab:"list",id:d})),[n,t]);return{...I,tab:Qe(t,Ge,ce),setTab:d=>n("connections",Pn(t,d,ce==="traffic"?ce:null)),openInList:nn,view:c,updateView:r,wide:o,text:g,setText:m,network:h,out:w,sel:M,select:D,collection:Ye,rows:S,outboundKeys:W,latency:f,latencyError:C,retryLatency:B.refetch,setNetwork:d=>R("network",d),setOut:d=>R("out",d),pick:re,compact:a,filterMenu:en,columns:G.map(d=>({id:d.id,label:e(d.label)})),visibleColumns:G.filter(d=>!c.hidden.includes(d.id)).map(d=>d.id),toggleColumn:d=>{const x=String(d),ne=c.hidden.includes(x)?c.hidden.filter(tn=>tn!==x):[...c.hidden,x];ne.length{m(""),n("connections",q(t,{network:null,out:null,rule:null,q:null,src:null}))},error:b.error,retry:b.refetch,loading:b.loading&&!b.data,truncated:!!b.data?.truncated,canClose:T,canViewFlow:F,closeAll:{confirmationText:_?.query?e(_.query.type==="all"?"conn.closeAllLive":_.query.type==="tcp"?"conn.closeAllLiveTcp":"conn.closeAllLiveUdp",k?{n:_.ids.length,src:k}:{n:_.ids.length,src:e("conn.anySource")}):e("conn.closeAllHelp",{n:_?.ids.length??0}),open:!!_,setOpen:d=>j(d?ft($,{network:h,src:k,narrowed:w!=="all"||u!=="all"||!!ee,truncated:!!b.data?.truncated,bulkLimit:N.data?.resources.connections.max_bulk_close}):null),isDisabled:!$.length||!!P.busy||g!==V,isPending:P.busy==="all",onConfirm:qe,onAbort:P.cancel},close:{pending:P.busy===U?.id,disabled:!!P.busy,run:()=>void Ze()},ruleAction:$e,showRule:()=>{U?.rule_id&&n("rules",oe("",{tab:"list",rule:U.rule_id}))},showFlow:()=>{I.detail&&F&&n("rules",I.detail.flowQuery)},onlyClient:()=>{I.detail?.source&&(m(""),n("connections",q(t,{src:I.detail.source,q:null})))},canExport:$.length>0,export:()=>Yn(Zn("connections","csv"),ht($,L),"text/csv;charset=utf-8"),detailTitle:I.detail?.title??"",notInSnapshot:!!M&&!U&&!!b.data}}function Wt(n){const t=J(),e=Nt(n),l=e.detail,c=s.jsxs(s.Fragment,{children:[e.error&&s.jsx(xe,{error:e.error,onRetry:e.retry}),s.jsxs("div",{className:"rp-toolbar",children:[e.compact?s.jsxs("span",{className:"rp-filter-row",children:[s.jsx(Ce,{search:!0,label:t("ui.filter"),value:e.text,onChange:e.setText,placeholder:t("conn.filterHint"),className:"rp-filter"}),s.jsx(de,{label:e.filterMenu.active?t("conn.filtersActive",{n:e.filterMenu.active}):t("conn.filters"),count:e.filterMenu.active,submenus:e.filterMenu.submenus,children:t("conn.filters")})]}):s.jsxs(s.Fragment,{children:[s.jsx(Ce,{search:!0,label:t("ui.filter"),value:e.text,onChange:e.setText,placeholder:t("conn.filterHint"),className:"rp-filter"}),s.jsx(We,{label:t("ui.network"),value:e.network,onChange:e.setNetwork,items:e.networks}),s.jsx(ae,{label:t("ui.outbound"),side:!0,value:e.out,onChange:e.setOut,items:e.outbounds}),s.jsx(de,{quiet:!0,label:t("conn.pick"),sections:e.picks,onAction:e.pick,children:t("conn.pick")})]}),s.jsx(ae,{label:t("conn.group"),side:!0,value:e.view.group,onChange:i=>e.updateView({group:i}),items:[{id:"source",label:t("conn.byClient")},{id:"outbound",label:t("ui.outbound")},{id:"none",label:t("conn.ungrouped")}]}),s.jsx(de,{label:t("conn.columns"),selectionMode:"multiple",items:e.columns,value:e.visibleColumns,onAction:e.toggleColumn,children:t("conn.columns")}),e.filtered&&s.jsx(O,{quiet:!0,onPress:e.clear,children:t("ui.clearFilters")}),e.truncated&&s.jsx(be,{tone:"warn",children:t("conn.truncated")}),e.visibility&&s.jsx(te,{text:t("conn.visibilityNote"),children:s.jsx(be,{children:e.visibility})}),s.jsx("span",{className:"rp-grow"}),e.canClose&&s.jsx(Bn,{label:t("conn.closeAll"),...e.closeAll}),s.jsxs(O,{isDisabled:!e.canExport,onPress:e.export,children:[s.jsx(Ie,{}),t("conn.export")]})]}),s.jsxs("div",{className:"rp-with-panel","data-open":l?"":void 0,children:[s.jsx(gt,{collection:e.collection,loading:e.loading,selected:e.sel,onSelect:e.select,selectOnFocus:e.wide,view:e.view,onSort:i=>e.updateView({sort:i})}),s.jsx(In,{open:!!l,title:e.detailTitle,onClose:()=>e.select(null),children:l&&s.jsxs(s.Fragment,{children:[s.jsx(En,{small:!0,tone:l.tone,children:l.status}),s.jsxs("div",{className:"rp-cluster",children:[s.jsxs("div",{className:"rp-cluster",children:[e.ruleAction.canAdd&&s.jsx(O,{onPress:e.ruleAction.openAdd,children:t("rule.add")}),e.ruleAction.canShow&&s.jsx(O,{onPress:e.showRule,children:t("conn.showRule")}),e.canViewFlow&&s.jsx(O,{onPress:e.showFlow,children:t("conn.viewFlow")}),l.source&&s.jsx(O,{onPress:e.onlyClient,children:t("conn.onlyThisClient")})]}),e.canClose&&l.closable&&s.jsx(O,{negative:!0,quiet:!0,isPending:e.close.pending,isDisabled:e.close.disabled,onPress:e.close.run,children:t("conn.close")})]}),s.jsx(Me,{items:l.fields}),s.jsx(Me,{items:[[t("ui.outbound"),l.outbound],[t("conn.chain"),l.chain]]}),s.jsxs("div",{className:"rp-list",children:[s.jsx("span",{className:"rp-label",children:t("conn.rule")}),s.jsx(Ve,{...l.rule})]})]})})]}),e.notInSnapshot&&s.jsx("span",{className:"rp-label",children:t("conn.notInSnapshot")}),s.jsx(wt,{dialog:e.ruleAction.dialog})]});return s.jsx("div",{className:"rp-page",children:s.jsx(Vn,{keepMounted:!0,label:t("nav.connections"),value:e.tab,onChange:e.setTab,items:[{id:"traffic",label:t("conn.tab.traffic"),content:s.jsx(lt,{records:e.rows,outbounds:e.outboundKeys,latency:e.latency,latencyError:e.latencyError,retryLatency:e.retryLatency,truncated:e.truncated,onSelect:e.openInList})},{id:"list",label:t("conn.tab.list"),content:c}]})})}export{Wt as Connections};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Connections-L2aJE6s8.js b/luci-app-honk/root/etc/honk/dashboard/assets/Connections-L2aJE6s8.js
new file mode 100644
index 000000000..7c8f0af32
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Connections-L2aJE6s8.js
@@ -0,0 +1,3 @@
+import{j as s,r as g}from"./vendor-react-Bf71BWbF.js";import{aM as fn,aN as gn,aO as fe,aP as de,u as Y,aB as Ge,a2 as ve,a as ye,ap as te,aQ as ee,aR as xn,aF as Je,aS as wn,aG as ge,E as je,a1 as ie,aT as vn,aU as yn,V as ue,X as re,Z as jn,a0 as ke,aV as _e,aW as Xe,aX as xe,aq as kn,aY as _n,aZ as Cn,a_ as Nn,au as Ae,a$ as Mn,b0 as Ye,aH as we,aE as le,ac as Ln,I as Te,b1 as Ze,b2 as ce,B as F,b3 as Sn,b4 as An,b5 as $e,b6 as Tn,a5 as qe,a7 as G,ab as Pn,a9 as Rn,b7 as Dn,b8 as Fn,b9 as On,ba as In,bb as J,f as Pe,bc as Bn,U as Wn,a6 as En,bd as Hn,Y as Un,a8 as Vn,be as Kn,bf as ze,bg as Qn,b as Re,bh as Gn,bi as Jn,A as Xn,T as De,bj as me,bk as Yn,bl as Zn,bm as $n,aC as qn,aD as Fe,bn as zn}from"./index-CXHBmSa5.js";import{F as et}from"./FactStrip-BgQ_tYB6.js";import{B as nt,r as tt}from"./ranked-FVqORIQj.js";import{u as st,C as ot,s as Oe,a as at,p as Ie}from"./layout-BRLew_nj.js";import{D as lt}from"./Table-D0NFHHNQ.js";import{T as it}from"./TimeCell-gSIuLEFc.js";import{t as z,r as en,w as Be,a as rt}from"./link-D6L0Eg5i.js";import{c as We,d as ct,e as dt}from"./files-BxEOxSF8.js";import{D as ut}from"./DaeCode-STEiRZuV.js";import{u as pt}from"./outbounds-f8QoVoCV.js";import{u as bt}from"./flows-C0byZ3sY.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";const Q=64,mt=22,q=8,ht=28;function ft({label:e,series:t,fmt:n,onSelect:a,regions:r,height:i=260}){const o=fn(),[l,c]=gn(),{ref:u,tip:j,show:b,hide:m}=st(),M=Math.max(1,...t.flatMap(h=>h.points.flatMap(A=>[A.x,A.y]))),{end:k,ticks:w}=at(M),p=Math.max((c??0)-Q-ht,1),N=i-q-mt,v=h=>Q+Oe(h,k)*p,y=h=>q+(1-Oe(h,k))*N,L=new Map,R=t.flatMap(h=>h.points.map(A=>{const _=v(A.x),C=y(A.y),T=_+","+C,B=L.get(T)??0;return L.set(T,B+1),{point:A,color:h.color,cx:_,cy:C,nth:B,spot:T}})).map(h=>({...h,twins:L.get(h.spot)}));return s.jsx("div",{className:"rp-scatter",ref:l,children:s.jsxs("div",{className:"rp-chart-hover",ref:u,onPointerLeave:m,children:[c!==null&&s.jsxs("svg",{width:c,height:i,role:"img","aria-label":e,"aria-describedby":o,children:[w.map(h=>s.jsxs("g",{children:[s.jsx("line",{className:"grid",x1:v(h),x2:v(h),y1:q,y2:q+N}),s.jsx("line",{className:"grid",x1:Q,x2:Q+p,y1:y(h),y2:y(h)}),s.jsx("text",{className:"tick",x:v(h),y:i-6,textAnchor:"middle",children:n(h)}),s.jsx("text",{className:"tick",x:Q-8,y:y(h)+4,textAnchor:"end",children:n(h)})]},h)),r&&s.jsxs("g",{className:"diagonal",children:[s.jsx("line",{x1:v(0),y1:y(0),x2:v(k),y2:y(k)}),s.jsx("text",{x:Q+8,y:q+14,children:r.above}),s.jsx("text",{x:Q+p-8,y:q+N-8,textAnchor:"end",children:r.below})]}),R.map(({point:h,color:A,cx:_,cy:C,nth:T,twins:B})=>{const O=2*Math.PI*T/B,U=B>1?6:0;return s.jsx("circle",{className:a?"pick":void 0,cx:_+U*Math.cos(O),cy:C+U*Math.sin(O),r:5,fill:A,onClick:a?()=>a(h.id):void 0,onPointerMove:D=>b(D,[h.name,h.detail])},h.id)})]}),s.jsx(ot,{tip:j})]})})}function gt({series:e}){return s.jsx("div",{className:"rp-legend",children:e.map(t=>s.jsx(fe,{swatch:t.color,label:t.label,value:String(t.points.length)},t.id))})}function xt(e){const t=new Map;let n=0;for(const o of e){if(o.upload_bytes===null||o.download_bytes===null){n++;continue}const l={id:o.id,up:Number(o.upload_bytes),down:Number(o.download_bytes),name:o.domain||o.dst||o.id},c=t.get(o.outbound);c?c.push(l):t.set(o.outbound,[l])}const a=[...t].map(([o,l])=>({outbound:o,points:l})).sort((o,l)=>de(o.outbound??"",l.outbound??""));let r,i=-1n;for(const o of e){if(o.upload_bytes===null||o.download_bytes===null)continue;const l=BigInt(o.upload_bytes)+BigInt(o.download_bytes);l>i&&(i=l,r={id:o.id,up:Number(o.upload_bytes),down:Number(o.download_bytes),name:o.domain||o.dst||o.id,outbound:o.outbound})}return{series:a,unknown:n,heaviest:r,placed:e.length-n}}const Ee=[0,2,3,1,4,5,6,7],wt=g.memo(function({records:t,outbounds:n,latency:a,latencyError:r,retryLatency:i,truncated:o,onSelect:l}){const c=Y(),u=Ge(),j=ve[ye()],b=g.useCallback(p=>te(p,j),[j]),m=g.useMemo(()=>xt(t),[t]),M=g.useMemo(()=>{const p=n.filter(v=>v!=="block"),N=v=>v==="block"?u.negative:u.cat[Ee[Math.max(0,p.indexOf(v))%Ee.length]];return m.series.map(v=>({id:v.outbound??"",label:ee(v.outbound,c),color:N(v.outbound),points:v.points.map(y=>({id:y.id,x:y.up,y:y.down,name:y.name,detail:c("conn.chart.point",{down:b(y.down),up:b(y.up)})}))}))},[m,n,u,c,b]),k=m.heaviest?[{label:c("conn.chart.busiest"),icon:s.jsx(xn,{}),tint:"c3",value:m.heaviest.name,caption:ee(m.heaviest.outbound,c)},{label:c("conn.chart.down"),value:b(m.heaviest.down),icon:s.jsx(Je,{}),tint:"c1"},{label:c("conn.chart.up"),value:b(m.heaviest.up),icon:s.jsx(wn,{}),tint:"c4"}]:[],w=m.unknown?c("conn.chart.sampleUnknown",{n:t.length,unknown:m.unknown}):c("conn.chart.sample",{n:t.length});return s.jsxs("div",{className:"rp-chart-page",children:[s.jsx(et,{facts:k,lead:!0}),s.jsxs(ge,{title:c("conn.chart.title"),note:w,children:[o&&s.jsx("p",{className:"rp-note",children:c("conn.truncated")}),m.placed>0&&s.jsxs(s.Fragment,{children:[s.jsx(ft,{label:c("conn.chart.title"),series:M,fmt:b,onSelect:l,regions:{above:c("conn.chart.moreDown"),below:c("conn.chart.moreUp")}}),s.jsx(gt,{series:M}),s.jsx("p",{className:"rp-note",children:c("conn.chart.hint")})]})]}),a?s.jsx(vt,{latency:a}):r&&s.jsx(ge,{title:c("ui.nodeLatency"),children:s.jsx(je,{error:r,onRetry:i})})]})});function vt({latency:e}){const t=Y(),n=Ge(),a=o=>vn(o,t),r=ve[ye()],i=o=>!e.chains||o?n.cat[0]:n.muted;return s.jsx(ge,{title:t("ui.nodeLatency"),note:t("conn.latency.sample",{n:e.samples.length,missing:e.missing}),children:e.samples.length?s.jsxs(s.Fragment,{children:[s.jsx("p",{className:"rp-note",children:t("conn.latency.percentiles",{p50:a(e.p50),p90:a(e.p90)})}),e.weightedP50!==null&&s.jsx("p",{className:"rp-note",children:e.unplaced?t("conn.latency.weightedUnplaced",{p50:a(e.weightedP50),n:e.unplaced}):t("conn.latency.weighted",{p50:a(e.weightedP50)})}),s.jsx(nt,{label:t("ui.nodeLatency"),points:e.samples.map(o=>({id:o.node,value:o.value,color:i(o.connections>0),lines:[o.name,a(o.value),...o.connections?[t("conn.chart.sample",{n:o.connections})]:[]]})),fmt:a}),e.chains&&s.jsxs("div",{className:"rp-legend",children:[s.jsx(fe,{swatch:i(!0),label:t("conn.latency.inUse"),value:ie(e.used,r)}),s.jsx(fe,{swatch:i(!1),label:t("conn.latency.others"),value:ie(e.samples.length-e.used,r)})]}),s.jsx("p",{className:"rp-note",children:t("conn.latency.hint")})]}):s.jsx("p",{className:"rp-note",children:t("conn.latency.pending")})})}const He={userspace:"conn.observed.userspace",ebpf:"conn.observed.ebpf",mixed:"conn.observed.mixed"};function yt(e,t){return[["ui.device",e.src??"—"],["conn.f.dst",e.dst??"—"],["ui.domain",e.domain??"—"],["conn.f.ingress",Be(e.ingress)],["conn.f.domainSource",Be(e.domain_source)],["ui.process",e.pname??"—"],["conn.f.observedBy",He[e.observed_by]?{key:He[e.observed_by]}:e.observed_by],["ui.upload",te(e.upload_bytes,t)],["ui.download",te(e.download_bytes,t)],["conn.f.uploadRate",xe(e.upload_bytes_per_second,t)],["conn.f.downloadRate",xe(e.download_bytes_per_second,t)],["conn.f.started",kn(e.started_at,t)]]}const X=[{id:"dst",label:"ui.target",minWidth:200,sortable:!0},{id:"src",label:"ui.device",minWidth:128,sortable:!0,drop:5},{id:"node",label:"conn.node",minWidth:120,drop:3},{id:"rule",label:"conn.rule",minWidth:220,drop:2},{id:"state",label:"ui.state",minWidth:88,sortable:!0,drop:7},{id:"down",label:"ui.download",minWidth:96,align:"end",sortable:!0,drop:4},{id:"downRate",label:"conn.f.downloadRate",minWidth:128,align:"end",sortable:!0,drop:1},{id:"age",label:"ui.started",minWidth:132,align:"end",sortable:!0,drop:6}],Ue=yn.connectionsView,he=e=>({allCollapsed:e,exceptions:new Set}),nn=(e,t)=>e.allCollapsed!==e.exceptions.has(t);function tn(e,t){const n=new Set(e.exceptions);return n.delete(t)||n.add(t),{allCollapsed:e.allCollapsed,exceptions:n}}const jt=(e,t)=>nn(e,t)?tn(e,t):e,sn=(e,t)=>t==="source"?ue(e.src??void 0)??e.src??"—":e.outbound??"unknown",kt=(e,t,n)=>t==="source"?e:ee(e,n),_t=e=>"g:"+e,Ce=e=>e.startsWith("g:")||e.startsWith("\\")?"\\"+e:e,Ct=e=>e.startsWith("\\")?e.slice(1):e;function Nt(e,t){if(!e||t==="none")return null;const n=sn(e,t);return{group:n,token:JSON.stringify([e.id,t,n])}}function Ve(e){const t={hidden:[],sort:null,group:"source"};try{const n=JSON.parse(e??"null");if(!n||typeof n!="object")return t;const a=Array.isArray(n.hidden)?n.hidden.map(o=>o==="chain"?"node":o):[],r=X.filter(o=>a.includes(o.id)).map(o=>o.id),i=n.sort;return{hidden:r.length===X.length?[]:r,sort:i&&X.some(o=>o.sortable&&o.id===i.column)&&["ascending","descending"].includes(i.direction)?{column:i.column,direction:i.direction}:null,group:n.group==="none"||n.group==="outbound"?n.group:"source"}}catch{return t}}function Mt(e,t,n){return e.map(a=>({item:a,key:t(a)})).sort((a,r)=>n(a.key,r.key)).map(a=>a.item)}function Lt(e,t,n){let a=e;if(t.sort){const{column:i,direction:o}=t.sort;a=Mt(e,c=>{switch(i){case"dst":return c.domain||c.dst;case"src":return c.src;case"state":return ke(_e,c.state,n);case"down":return Ae(c.download_bytes);case"downRate":return Ae(c.download_bytes_per_second);case"age":return c.started_at?Date.parse(c.started_at):null;default:return null}},(c,u)=>{if(c==null)return u==null?0:1;if(u==null)return-1;const j=typeof c=="string"&&typeof u=="string"?de(c,u):cu?1:0;return o==="descending"?-j:j})}if(t.group==="none")return a.map(i=>({id:Ce(i.id),connection:i}));const r=new Map;for(const i of a){const o=sn(i,t.group),l=r.get(o);l?l.push(i):r.set(o,[i])}return[...r].map(([i,o])=>({id:_t(i),group:i,children:o,active:o.filter(l=>l.state==="active").length,download:_n(...o.map(l=>l.download_bytes))}))}const Ke=new WeakMap;function St(e,t,n,a,r,i){const o=l=>{const c=Ke.get(l);if(c&&c.locale===n&&c.names===a&&c.rulesListed===r&&c.t===i)return c.row;const u={id:Ce(l.id),target:l.domain||l.dst||"—",source:l.src??"—",node:Nn(l,i,a),path:Cn(l,i,a),rule:{expression:l.rule_expression,href:en(l.rule_id,r)},recomputed:l.rule_source==="recomputed"?i("conn.recomputed"):null,state:ke(_e,l.state,i),download:te(l.download_bytes,n),downloadRate:xe(l.download_bytes_per_second,n),startedAt:l.started_at};return Ke.set(l,{locale:n,names:a,rulesListed:r,t:i,row:u}),u};return Lt(e,t,i).map(l=>"connection"in l?{id:l.id,connection:o(l.connection)}:{id:l.id,group:l.group,children:l.children.map(o),label:i("conn.groupCount",{name:kt(l.group,t.group,i),n:l.children.length}),totals:{down:te(l.download,n),state:i("conn.activeCount",{n:l.active})}})}function At(e,t,n,a,r,i){const o=l=>{const c=l.flatMap(u=>u?[u]:[]);return tt(c,12).top};return{networks:[["all",i("ui.allCount",{n:e.length})],["tcp",i("ui.tcp")],["udp",i("ui.udp")]],outbounds:[{id:"all",label:i("conn.allOutbounds")},...[...new Set(e.flatMap(l=>l.outbound?[l.outbound]:[]))].map(l=>({id:l,label:ee(l,i)}))],picks:[{title:i("ui.device"),value:z("src",n??""),items:o(e.map(l=>ue(l.src))).map(({key:l,count:c})=>({id:z("src",l),label:l,desc:ie(c,r)}))},{title:i("conn.rule"),value:z("rule",a),items:o(e.map(l=>l.rule_expression)).map(({key:l,count:c})=>({id:z("rule",l),label:l,desc:ie(c,r)}))}],visibility:t&&t.visibility!=="full"?i(t.visibility==="none"?"conn.visibilityNone":"conn.visibilityPartial"):null}}function Tt(e,t,n){const[a,r]=e.picks,i=(o,l,c,u)=>({filter:o,label:l,sections:[{title:l,items:c,value:u}]});return{active:[t.network!=="all",t.out!=="all",!!t.src,t.rule!=="all"].filter(Boolean).length,submenus:[i("network",n("ui.network"),e.networks.map(([o,l])=>({id:o,label:l})),t.network),i("out",n("ui.outbound"),e.outbounds,t.out),i("src",a.title,[{id:z("src",""),label:n("conn.allDevices")},...a.items],a.value),i("rule",r.title,[{id:z("rule","all"),label:n("conn.allRules")},...r.items],r.value)]}}const Qe={observed:["conn.state.observed","conn.stateHelp.observed"],routing:["conn.state.routing","conn.stateHelp.routing"],dialing:["conn.state.dialing","conn.stateHelp.dialing"]};function Pt(e,t){return Object.hasOwn(Qe,e)?{title:t("ui.state"),text:Object.values(Qe).map(([n,a])=>t("ui.valuePair",{label:t(n),value:t(a)}))}:null}function Rt(e,t,n,a,r){return e?{id:e.id,title:e.domain||e.dst||e.id,tone:e.state==="blocked"||e.state==="failed"?"err":e.state==="active"?"ok":"info",status:n("ui.aside",{text:ke(_e,e.state,n),note:e.network.toUpperCase()}),chain:jn(e,n,a),outbound:ee(e.outbound,n),rule:{expression:e.rule_expression,href:en(e.rule_id,r)},fields:yt(e,t).map(([i,o])=>[n(i),typeof o=="string"?o:n(o.key,o.params)]),flowQuery:re("",{tab:"flows",...e.flow_id?{id:e.flow_id}:{connection_id:e.id}}),source:e.src?ue(e.src)??e.src:null,closable:e.state==="active"||e.state==="dialing"||e.state==="routing",stateHelp:Pt(e.state,n)}:null}function Dt(e,t){return[We(["id","target","domain","source","network","state","outbound","chain","rule","upload_bytes","download_bytes","started_at"]),...e.map(n=>We([n.id,n.dst,n.domain,n.src,n.network,n.state,n.outbound,Xe(n.chain,t).join(" > "),n.rule_expression,n.upload_bytes,n.download_bytes,n.started_at]))].join(`
+`)+`
+`}function Ft(e,t){const n=e.map(r=>r.id),a=t.bulkLimit!=null&&n.length>t.bulkLimit;return t.narrowed||t.truncated||a?{ids:n}:{ids:n,query:{type:t.network,src:t.src,all:!0}}}const Ot=e=>e.target;function It({collection:e,view:t,collapse:n,onToggleGroup:a,loading:r,selected:i,onSelect:o,selectOnFocus:l,onSort:c}){const u=Y(),[j,b]=Mn(442),m=g.useMemo(()=>{const w={dst:p=>s.jsx(le,{children:p.target}),src:p=>s.jsx(le,{className:"rp-code",children:p.source}),node:p=>s.jsx(le,{className:"rp-chain",text:p.path??void 0,children:p.node}),rule:p=>s.jsxs("span",{className:"rp-rule",children:[s.jsx(Ye,{...p.rule}),p.recomputed&&s.jsx(we,{children:p.recomputed})]}),state:p=>p.state,down:p=>p.download,downRate:p=>p.downloadRate,age:p=>s.jsx(it,{at:p.startedAt})};return X.filter(p=>!t.hidden.includes(p.id)).map(p=>({...p,label:u(p.label),grow:1,render:w[p.id]}))},[t.hidden,u]),M=g.useMemo(()=>e.map(w=>"connection"in w?w.connection:w),[e]),k=g.useMemo(()=>({grouped:t.group!=="none",collapsed:w=>nn(n,w),onToggle:a}),[t.group,n,a]);return s.jsx("div",{ref:j,children:s.jsx(lt,{label:u("nav.connections"),rowDetail:!0,cols:m,rows:M,height:b,selected:i&&Ce(i),onSelect:o&&(w=>o(w&&Ct(w))),selectOnFocus:l,reveal:!0,empty:u("conn.empty"),loading:r,sort:t.sort&&{column:String(t.sort.column),direction:t.sort.direction},onSort:c,getTextValue:Ot,stream:!0,tree:k})})}function Bt({dialog:e}){const t=Y();return s.jsxs(Ln,{title:t("rule.add"),narrow:!0,isOpen:!!e,reason:e?.reason,onOpenChange:n=>{n||e?.close()},footer:()=>s.jsxs(s.Fragment,{children:[s.jsx(F,{onPress:()=>e?.close(),children:t("ui.cancel")}),s.jsx(F,{isDisabled:e?.disabled,isPending:e?.busy,onPress:()=>e?.applyNow(),children:t("rule.addApply")}),s.jsx(F,{accent:!0,isDisabled:e?.disabled||e?.busy,onPress:()=>e?.hold(),children:t("rule.hold")})]}),children:[e?.failure&&s.jsx(Te,{takeFocus:!0,children:e.failure.text},e.failure.id),e&&s.jsxs("div",{className:"rp-list",children:[e.failure?.lines.map((n,a)=>s.jsx("span",{className:"rp-label",children:n},a)),s.jsx(je,{error:e.loadError,onRetry:e.retry}),s.jsx("span",{className:"rp-label",children:t("rule.holdHelp")}),e.targets&&s.jsx(Ze,{isDisabled:e.busy,label:t("rule.kind"),value:e.target,onChange:e.setTarget,items:e.targets}),s.jsxs("div",{className:"rp-toolbar top",children:[s.jsx(ce,{isDisabled:e.busy,label:t("ui.outbound"),value:e.outbound,onChange:e.setOutbound,items:e.outbounds}),s.jsx(ce,{isDisabled:e.busy||!e.positions.length,label:t("rule.position"),value:e.before,onChange:e.setBefore,items:e.positions})]}),e.moved&&s.jsx(Te,{tone:"informative",children:t("conn.ruleMoved")}),e.unplaceable&&s.jsx("p",{className:"rp-note",children:t("conn.ruleNoPosition")}),s.jsx(ut,{text:e.preview})]})]})}function Wt(e,t){if(!t.some(b=>b.health?.length))return null;const n=[];let a=0;for(const b of t){const m=Sn(An(b.health??[]));m===void 0?a++:n.push({node:b.id,name:b.name,value:m,connections:0})}n.sort((b,m)=>b.value-m.value||de(b.name,m.name));const r=new Map(n.map(b=>[b.node,b])),i=e.some(b=>b.chain?.length);let o=0;for(const b of e){const m=b.chain?.at(-1);if(m===void 0)continue;const M=r.get(m);M?M.connections++:o++}const l=n.reduce((b,m)=>b+m.connections,0);let c=0;const u=n.find(b=>(c+=b.connections)>=Math.max(1,Math.ceil(l/2))),j=n.map(b=>b.value);return{samples:n,chains:i,missing:a,unplaced:o,used:n.filter(b=>b.connections).length,p50:Ie(j,50),p90:Ie(j,90),weightedP50:l?u.value:null}}function Et(e){const t=r=>r.flatMap(([i,o])=>{const l=Tn(i,o);return l?[{kind:i,condition:l}]:[]}),n=e.domain?t([["domain",e.domain],["domainSuffix",e.domain]]):[],a=ue(e.dst);return n.length?n:a?t([["dip",a]]):[]}function Ht(e,t,n,a){const r=c=>{const u=t.find(j=>j.id===c.source?.source_id);return!!u?.writable&&$e(u,c)!==null},i=e.find(c=>c.rule_id===n&&r(c)),o=e.find(r),l=c=>c===e[0]?a("conn.ruleTop"):a("rule.positionBefore",{n:c.index+1});return[...i?[{rule:i,label:a("conn.ruleBeforeMatched")}]:[],...o&&o!==i?[{rule:o,label:l(o)}]:[]].map(({rule:c,label:u})=>({id:c.rule_id,label:u,desc:c.expression}))}function Ut(e,t,n){if(!t)return{before:e[0]?.id,moved:!1};const a=e.find(r=>r.id===t.rule.rule_id&&(n===t.generation||r.desc===t.rule.expression));return a?{before:a.id,moved:!1}:{before:e[0]?.id,moved:!0}}function Vt({disabled:e,busy:t,failed:n,unplaceable:a},r){return e&&!t&&!n&&!a?r("ui.loading"):null}function Kt(e){const t=Y(),n=qe().data?.resources,a=G(n,"rules",{whileLoading:!1})&&G(n,"config",{whileLoading:!1})&&n?.config.writable===!0,[r,i]=g.useState(null),[o,l]=g.useState(null),c=!!r,u=bt(c),j=Pn(c),b=G(n,"groups",{whileLoading:!1}),m=Rn(c&&b),M=()=>{u.refetch(),j.refetch(),b&&m.refetch()},k=Dn(),w=j.data?.sources??[],p=Ht(u.data?.rules??[],w,r?.matched??null,t),N=Fn(m.data??[]),v=!b||!!m.data,y=r?.outbound||N.find(x=>x.id===r?.current)?.id||(v?N[0].id:""),L=u.data?.generation_id,Z=x=>{const S=u.data?.rules.find(K=>K.rule_id===x);return S&&L?{generation:L,rule:S}:null},{before:R,moved:h}=Ut(p,r?.pin??null,L),A=r&&!r.pin?Z(R):null;A&&i({...r,pin:A});const _=r?.targets[r.target],C=x=>{r&&!k.busy&&i({...r,...x})},T=()=>{k.busy&&(k.cancel(),M()),i(null),l(null)},B=()=>{J("negative",t("rule.stale")),M()},O=()=>{const x=u.data?.rules.find(K=>K.rule_id===R),S=w.find(K=>K.id===x?.source?.source_id);return!_||!x||!S||!$e(S,x)||u.data?.generation_id!==j.data?.generation_id?(B(),null):(h&&i({...r,pin:Z(R)}),{condition:_.condition,outbound:y,must:!1,before:x,sourceId:S.id})},U=()=>{const x=O();x&&(In.add(x),J("positive",t("rule.held")),T())},D=async()=>{const x=O();if(!x)return;l(null);const S=await k.apply([{...x,id:0}]);if(S){if(!S.written){l({id:Date.now(),...S.failure});return}J(S.failure?"negative":"positive",S.failure?S.failure.text:t("rule.added")),i(null)}},I=e?Et(e):[],P=u.error??j.error??m.error,V=!!u.data&&!!j.data&&!p.length,W=!_||!R||!v;return{canAdd:a&&I.length>0,canShow:G(n,"rules",{whileLoading:!1})&&!!e?.rule_id,openAdd:()=>{e&&i({targets:I,matched:e.rule_id,current:e.outbound,target:0,outbound:"",pin:null})},dialog:r&&{targets:r.targets.length>1?r.targets.map((x,S)=>[String(S),t(`rule.kind.${x.kind}`)]):null,target:String(r.target),setTarget:x=>C({target:Number(x)}),outbounds:N,outbound:y,setOutbound:x=>C({outbound:x}),positions:p,before:R??"",setBefore:x=>C({pin:Z(x)}),preview:_?y?On(_.condition,y):_.condition:"",busy:k.busy,loadError:P,retry:M,moved:h,unplaceable:V,disabled:W,reason:Vt({disabled:W,busy:k.busy,failed:!!P,unplaceable:V},t),failure:o,hold:U,applyNow:()=>void D(),close:T}}}const on=["traffic","list"],an=e=>["id","src","network","out","rule","q"].some(t=>new URLSearchParams(e).has(t))?"list":"traffic",ne=(e,t)=>re(e,an(e)==="list"?{tab:ze(e,on,"list"),...t}:t);function Qt({go:e,query:t}){const n=Y(),a=ve[ye()],[r,i]=g.useState(()=>{try{return Ve(localStorage.getItem(Ue))}catch{return Ve(null)}}),o=Pe(Jn),l=Pe(Gn),[c,u]=g.useState(()=>he(!1)),j=g.useCallback(d=>u(f=>tn(f,d)),[]),b=d=>{const f={...r,...d};f.group!==r.group&&u(he(!1)),i(f);try{localStorage.setItem(Ue,JSON.stringify(f))}catch{}},m=g.useMemo(()=>new URLSearchParams(t),[t]),[M,k]=g.useState(m.get("q")??""),w=m.get("network")??"all",p=m.get("out")??"all",N=m.get("rule")??"all",v=(d,f)=>e("connections",ne(t,{[d]:f==="all"?null:f})),y=m.get("id"),[L,Z]=g.useState(null);Bn(m.get("q"),d=>k(d??""));const R=g.useRef(t);g.useEffect(()=>{R.current=t});const h=d=>e("connections",ne(R.current,{id:d})),A=g.useDeferredValue(M),_=Wn(m.get("src")??""),C=En(_),T=qe(),B=T.data?.resources.connections.can_close===!0,O=G(T.data?.resources,"rules",{whileLoading:!1}),U=G(T.data?.resources,"flows",{whileLoading:!1}),D=pt(),I=Hn(C.refetch),P=g.useMemo(()=>Un(C.data),[C.data]),V=G(T.data?.resources,"nodes",{whileLoading:!1}),W=Vn(V),x=g.useMemo(()=>V&&W.data?Wt(P,W.data):null,[V,W.data,P]),S=V&&!W.data?W.error:null,K=g.useMemo(()=>[...new Set(P.map(d=>d.outbound))].sort((d,f)=>de(d??"",f??"")),[P]),se=A.trim().toLowerCase(),$=g.useMemo(()=>P.filter(d=>(w==="all"||d.network===w)&&(p==="all"||d.outbound===p)&&(N==="all"||d.rule_expression===N)&&(!se||[d.dst,d.domain,d.src,d.pname,ee(d.outbound,n),Xe(d.chain,D).join(" "),d.rule_expression].join(" ").toLowerCase().includes(se))),[P,w,p,N,se,D,n]),H=y?P.find(d=>d.id===y):void 0,[Ne,Me]=g.useState(null);!y&&Ne!==null&&Me(null);const oe=Nt(H,r.group);oe&&Ne!==oe.token&&(Me(oe.token),u(jt(c,oe.group)));const ln=Kt(H),Le=g.useMemo(()=>At(P,C.data,_,N,a,n),[P,C.data,_,N,a,n]),rn=g.useMemo(()=>Rt(H,a,n,D,O),[H,a,n,D,O]),E={...Le,detail:rn},cn=g.useMemo(()=>St($,r,a,D,O,n),[$,r,a,D,O,n]),dn=async()=>{if(!E.detail)return;const{id:d}=E.detail;try{if(!await I.close(d))return;new URLSearchParams(R.current).get("id")===d&&h(null),J("positive",n("conn.closed",{name:E.detail.title}))}catch(f){f instanceof Xn&&f.code==="state_conflict"?J("negative",n("conn.notClosable")):J("negative",n("conn.closeFailed"),{detail:Re(f,n)})}},un=async()=>{if(L)try{const d=await I.closeAll(L);if(!d)return;h(null),J(Qn(d),n("conn.closedAll",{closed:d.closed,skipped:d.skipped}))}catch(d){return n("ui.valuePair",{label:n("conn.closeFailed"),value:Re(d,n)})}},pe=d=>{const f=rt(String(d),["src","rule"]);f?.kind==="src"?(k(""),e("connections",ne(t,{src:!f.value||_===f.value?null:f.value,q:null}))):f?.kind==="rule"&&v("rule",N===f.value?"all":f.value)},Se=Tt(Le,{network:w,out:p,src:_,rule:N},n),pn={network:d=>v("network",d),out:d=>v("out",d),src:pe,rule:pe},bn={active:Se.active,submenus:Se.submenus.map(({filter:d,...f})=>({...f,sections:f.sections.map(ae=>({...ae,onChange:pn[d]}))}))},be=an(t),mn=g.useCallback(d=>e("connections",re(t,{tab:"list",id:d})),[e,t]);return{...E,tab:ze(t,on,be),setTab:d=>e("connections",Kn(t,d,be==="traffic"?be:null)),openInList:mn,view:r,updateView:b,collapse:c,toggleCollapse:j,toggleCollapseAll:()=>u(he(!c.allCollapsed)),wide:o,text:M,setText:k,network:w,out:p,sel:y,select:h,collection:cn,rows:P,outboundKeys:K,latency:x,latencyError:S,retryLatency:W.refetch,setNetwork:d=>v("network",d),setOut:d=>v("out",d),pick:pe,compact:l,filterMenu:bn,columns:X.map(d=>({id:d.id,label:n(d.label)})),visibleColumns:X.filter(d=>!r.hidden.includes(d.id)).map(d=>d.id),toggleColumn:d=>{const f=String(d),ae=r.hidden.includes(f)?r.hidden.filter(hn=>hn!==f):[...r.hidden,f];ae.length{k(""),e("connections",ne(t,{network:null,out:null,rule:null,q:null,src:null}))},error:C.error,retry:C.refetch,loading:C.loading&&!C.data,truncated:!!C.data?.truncated,canClose:B,canViewFlow:U,closeAll:{confirmationText:L?.query?n(L.query.type==="all"?"conn.closeAllLive":L.query.type==="tcp"?"conn.closeAllLiveTcp":"conn.closeAllLiveUdp",_?{n:L.ids.length,src:_}:{n:L.ids.length,src:n("conn.anySource")}):n("conn.closeAllHelp",{n:L?.ids.length??0}),open:!!L,setOpen:d=>Z(d?Ft($,{network:w,src:_,narrowed:p!=="all"||N!=="all"||!!se,truncated:!!C.data?.truncated,bulkLimit:T.data?.resources.connections.max_bulk_close}):null),isDisabled:!$.length||!!I.busy||M!==A,isPending:I.busy==="all",onConfirm:un,onAbort:I.cancel},close:{pending:I.busy===H?.id,disabled:!!I.busy,run:()=>void dn()},ruleAction:ln,showRule:()=>{H?.rule_id&&e("rules",re("",{tab:"list",rule:H.rule_id}))},showFlow:()=>{E.detail&&U&&e("rules",E.detail.flowQuery)},onlyClient:()=>{E.detail?.source&&(k(""),e("connections",ne(t,{src:E.detail.source,q:null})))},canExport:$.length>0,export:()=>ct(dt("connections","csv"),Dt($,D),"text/csv;charset=utf-8"),detailTitle:E.detail?.title??"",notInSnapshot:!!y&&!H&&!!C.data}}function is(e){const t=Y(),n=Qt(e),a=n.detail,r=s.jsxs(s.Fragment,{children:[n.error&&s.jsx(je,{error:n.error,onRetry:n.retry}),s.jsxs("div",{className:"rp-toolbar",children:[n.compact?s.jsxs("span",{className:"rp-filter-row",children:[s.jsx(De,{search:!0,label:t("ui.filter"),value:n.text,onChange:n.setText,placeholder:t("conn.filterHint"),className:"rp-filter"}),s.jsx(me,{label:n.filterMenu.active?t("conn.filtersActive",{n:n.filterMenu.active}):t("conn.filters"),count:n.filterMenu.active,submenus:n.filterMenu.submenus,children:t("conn.filters")})]}):s.jsxs(s.Fragment,{children:[s.jsx(De,{search:!0,label:t("ui.filter"),value:n.text,onChange:n.setText,placeholder:t("conn.filterHint"),className:"rp-filter"}),s.jsx(Ze,{label:t("ui.network"),value:n.network,onChange:n.setNetwork,items:n.networks}),s.jsx(ce,{label:t("ui.outbound"),side:!0,value:n.out,onChange:n.setOut,items:n.outbounds}),s.jsx(me,{quiet:!0,label:t("conn.pick"),sections:n.picks,onAction:n.pick,children:t("conn.pick")})]}),s.jsx(ce,{label:t("conn.group"),side:!0,value:n.view.group,onChange:i=>n.updateView({group:i}),items:[{id:"source",label:t("conn.byClient")},{id:"outbound",label:t("ui.outbound")},{id:"none",label:t("conn.ungrouped")}]}),n.view.group!=="none"&&s.jsx(F,{onPress:n.toggleCollapseAll,children:t(n.collapse.allCollapsed?"conn.expandAll":"conn.collapseAll")}),s.jsx(me,{label:t("conn.columns"),selectionMode:"multiple",items:n.columns,value:n.visibleColumns,onAction:n.toggleColumn,children:t("conn.columns")}),n.filtered&&s.jsx(F,{quiet:!0,onPress:n.clear,children:t("ui.clearFilters")}),n.truncated&&s.jsx(we,{tone:"warn",children:t("conn.truncated")}),n.visibility&&s.jsx(le,{text:t("conn.visibilityNote"),children:s.jsx(we,{children:n.visibility})}),s.jsx("span",{className:"rp-grow"}),n.canClose&&s.jsx(Yn,{label:t("conn.closeAll"),...n.closeAll}),s.jsxs(F,{isDisabled:!n.canExport,onPress:n.export,children:[s.jsx(Je,{}),t("conn.export")]})]}),s.jsxs("div",{className:"rp-with-panel","data-open":a?"":void 0,children:[s.jsx(It,{collection:n.collection,loading:n.loading,selected:n.sel,onSelect:n.select,selectOnFocus:n.wide,view:n.view,collapse:n.collapse,onToggleGroup:n.toggleCollapse,onSort:i=>n.updateView({sort:i})}),s.jsx(Zn,{open:!!a,title:n.detailTitle,onClose:()=>n.select(null),children:a&&s.jsxs(s.Fragment,{children:[s.jsx($n,{help:a.stateHelp,children:s.jsx(qn,{small:!0,tone:a.tone,children:a.status})}),s.jsxs("div",{className:"rp-cluster",children:[s.jsxs("div",{className:"rp-cluster",children:[n.ruleAction.canAdd&&s.jsx(F,{onPress:n.ruleAction.openAdd,children:t("rule.add")}),n.ruleAction.canShow&&s.jsx(F,{onPress:n.showRule,children:t("conn.showRule")}),n.canViewFlow&&s.jsx(F,{onPress:n.showFlow,children:t("conn.viewFlow")}),a.source&&s.jsx(F,{onPress:n.onlyClient,children:t("conn.onlyThisClient")})]}),n.canClose&&a.closable&&s.jsx(F,{negative:!0,quiet:!0,isPending:n.close.pending,isDisabled:n.close.disabled,onPress:n.close.run,children:t("conn.close")})]}),s.jsx(Fe,{items:a.fields}),s.jsx(Fe,{items:[[t("ui.outbound"),a.outbound],[t("conn.chain"),a.chain]]}),s.jsxs("div",{className:"rp-list",children:[s.jsx("span",{className:"rp-label",children:t("conn.rule")}),s.jsx(Ye,{...a.rule})]})]})})]}),n.notInSnapshot&&s.jsx("span",{className:"rp-label",children:t("conn.notInSnapshot")}),s.jsx(Bt,{dialog:n.ruleAction.dialog})]});return s.jsx("div",{className:"rp-page",children:s.jsx(zn,{keepMounted:!0,label:t("nav.connections"),value:n.tab,onChange:n.setTab,items:[{id:"traffic",label:t("conn.tab.traffic"),content:s.jsx(wt,{records:n.rows,outbounds:n.outboundKeys,latency:n.latency,latencyError:n.latencyError,retryLatency:n.retryLatency,truncated:n.truncated,onSelect:n.openInList})},{id:"list",label:t("conn.tab.list"),content:r}]})})}export{is as Connections};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-B4MDdwFy.js b/luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-STEiRZuV.js
similarity index 68%
rename from luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-B4MDdwFy.js
rename to luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-STEiRZuV.js
index 7727dc1ea..1e65a8732 100644
--- a/luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-B4MDdwFy.js
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/DaeCode-STEiRZuV.js
@@ -1,3 +1,3 @@
-import{r as o}from"./vendor-react-Bf71BWbF.js";const h=/^(global|dns|upstream|routing|request|response|subscription|node|group|include|fallback)\b/,p=()=>({afterArrow:!1});function l(t,e){return t.sol()&&(e.afterArrow=!1),t.eatSpace()?null:t.match("#")?(t.skipToEnd(),"comment"):t.match(/^'[^']*'/)||t.match(/^"[^"]*"/)?"string":t.match("->")?(e.afterArrow=!0,"operator"):e.afterArrow&&t.match(/^[\w.-]+/)?(e.afterArrow=!1,"keyword"):(t.sol()||t.string.slice(0,t.pos).trim()==="")&&t.match(h)?"keyword":t.match(/^\d+(\.\d+)*(\/\d+)?[a-z]*/)?"number":t.match(/^[\w.-]+(?=\s*\()/)?"propertyName":t.match(/^[\w.-]+(?=\s*:)/)?"variableName":t.match(/^[A-Za-z_][\w.-]*/)?null:t.match(/^[{}()&|!,:]/)?"punctuation":(t.next(),null)}class f{constructor(e){this.string=e}pos=0;sol(){return this.pos===0}eatSpace(){const e=/^\s+/.exec(this.string.slice(this.pos));return e?(this.pos+=e[0].length,!0):!1}match(e){const s=typeof e=="string"?this.string.slice(this.pos).startsWith(e)&&e:e.exec(this.string.slice(this.pos));return s&&(this.pos+=typeof s=="string"?s.length:s[0].length),s}skipToEnd(){this.pos=this.string.length}next(){return this.pos({afterArrow:!1});function l(t,e){return t.sol()&&(e.afterArrow=!1),t.eatSpace()?null:t.match("#")?(t.skipToEnd(),"comment"):t.match(/^'[^']*'/)||t.match(/^"[^"]*"/)?"string":t.match("->")?(e.afterArrow=!0,"operator"):e.afterArrow&&t.match(/^[\w.-]+/)?(e.afterArrow=!1,"keyword"):(t.sol()||t.string.slice(0,t.pos).trim()==="")&&t.match(h)?"keyword":t.match(/^\d+(\.\d+)*(\/\d+)?[a-z]*/)?"number":t.match(/^[\w.-]+(?=\s*\()/)?"propertyName":t.match(/^[\w.-]+(?=\s*:)/)?"variableName":t.match(/^[A-Za-z_][\w.-]*/)?null:t.match(/^[{}()&|!,:]/)?"punctuation":(t.next(),null)}class f{pos=0;string;constructor(e){this.string=e}sol(){return this.pos===0}eatSpace(){const e=/^\s+/.exec(this.string.slice(this.pos));return e?(this.pos+=e[0].length,!0):!1}match(e){const s=typeof e=="string"?this.string.slice(this.pos).startsWith(e)&&e:e.exec(this.string.slice(this.pos));return s&&(this.pos+=typeof s=="string"?s.length:s[0].length),s}skipToEnd(){this.pos=this.string.length}next(){return this.pos{const i=new f(n);for(;i.posr.type?o.createElement("span",{key:n,className:`rp-dae-${r.type}`},r.text):r.text))}export{m as D,l as d,p as s};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Dns-BCY3zvs7.js b/luci-app-honk/root/etc/honk/dashboard/assets/Dns-BCY3zvs7.js
deleted file mode 100644
index fe7ba2d8c..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Dns-BCY3zvs7.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import{r as m,j as a}from"./vendor-react-Bf71BWbF.js";import{u as g,aB as ye,bd as we,V as Ne,aI as j,ah as Ce,W as ne,ad as Te,A as _e,al as Se,be as re,$ as V,b2 as q,bf as le,Q as Y,b5 as De,b4 as Le,X as $,_ as I,bg as Z,N as Re,b1 as Ae,b8 as Ee,bh as qe,b0 as O,a as B,a1 as Fe,bi as Me,aE as ke,a8 as C,b as ie,E as R,as as Q,bj as Oe,bk as Pe,bl as We,bm as Be,ax as L,aD as ee,az as ce,aS as Ue,T as U,aT as oe,B as F,bn as He,ay as de,au as z,bc as Ve,av as D,at as se,aw as $e,bo as Ie,bb as Qe,ba as ze}from"./index-zQjLFfuj.js";import{D as ue}from"./Table-DLlwyNFJ.js";import{T as H}from"./TimeCell-DxlzlVpw.js";import{A as Ke}from"./ActionGroup-C-LVMOvQ.js";import{q as Xe,u as me,a as Ge,s as Je,b as Ye}from"./dns-BoPCaePc.js";import{c as ae,d as Ze,e as es}from"./files-BxEOxSF8.js";import{d as ss}from"./nav--TYgv3Ng.js";import{F as as}from"./FactStrip-vcLr7nBw.js";import{r as te,B as ts}from"./ranked-C_Wt6A1w.js";import{u as ns,w as rs,C as ls,p as P}from"./layout-B3T-zLsm.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";function is({label:r,shares:t}){const e=g(),s=ye(),{ref:i,tip:n,show:l,hide:c}=ns(),o=m.useMemo(()=>{const u=rs(t.map(h=>h.count));return t.flatMap((h,x)=>Array.from({length:u[x]},()=>h))},[t]);return a.jsxs("div",{className:"rp-waffle rp-chart-hover",ref:i,onPointerLeave:c,children:[a.jsx("div",{className:"grid",role:"img","aria-describedby":s,"aria-label":e("ui.valuePair",{label:r,value:t.map(u=>`${u.label} ${u.text}`).join(e("ui.separator"))}),children:o.map((u,h)=>a.jsx("span",{style:{background:u.color},onPointerMove:x=>l(x,[u.label,u.text])},h))}),a.jsx("ul",{className:"legend",children:t.map(u=>a.jsxs("li",{children:[a.jsx("i",{className:"sw",style:{background:u.color}}),a.jsx("span",{children:u.label}),a.jsx("b",{children:u.text})]},u.id))}),a.jsx(ls,{tip:n})]})}function cs({className:r,...t}){return a.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:we("rp-icon",r),...t,children:[a.jsx("path",{fill:"currentColor",d:"M8.249 15.021c-.4 0-.733-.317-.748-.72l-.25-6.5c-.017-.414.307-.763.72-.779H8c.4 0 .733.317.748.72l.25 6.5c.017.414-.307.763-.72.778zM11.751 15.021h-.03c-.413-.016-.737-.365-.72-.779l.25-6.5c.015-.403.348-.72.748-.72h.03c.413.016.737.365.72.779l-.25 6.5c-.015.403-.348.72-.748.72"}),a.jsx("path",{fill:"currentColor",d:"M17 4h-3.5v-.75C13.5 2.01 12.49 1 11.25 1h-2.5C7.51 1 6.5 2.01 6.5 3.25V4H3c-.414 0-.75.336-.75.75s.336.75.75.75h.52l.422 10.342C3.99 17.052 4.98 18 6.19 18h7.62c1.211 0 2.2-.948 2.248-2.158L16.48 5.5H17c.414 0 .75-.336.75-.75S17.414 4 17 4m-9-.75c0-.413.337-.75.75-.75h2.5c.413 0 .75.337.75.75V4H8zm6.56 12.531c-.017.404-.346.719-.75.719H6.19c-.404 0-.733-.315-.75-.719L5.02 5.5h9.96z"})]})}const os={forced:"dns.route.forced","dns.routing":"dns.route.rules",default:"dns.route.default"};function pe(r,t){return{fields:[[t("ui.state"),r.status],[t("ui.upstream"),r.upstream??"—"],[t("dns.routeSource"),Ne(os,r.route.source,t)],[t("dns.routeRule"),r.route.rule??"—"],[t("ui.elapsed"),j(r.elapsed_ms,t)]],answers:(r.answers??[]).map(e=>t("dns.answer",{name:e.name,type:e.type,ttl:e.ttl,data:e.data})),cacheText:t(r.cached?"dns.hit":"dns.miss"),cacheTone:r.cached?void 0:"warn"}}function ds(r,t,e,s,i,n){const l=t?.dns_query.record_types??[];return{types:l,choices:[...l.map(c=>({id:c,label:c})),{id:"all",label:n("dns.allTypes")}],disabled:i||!t?.dns_query.available||!(e==="all"?l.length>0:l.includes(e))||!s.trim(),showCache:!!t?.dns_cache.available,cards:r?.results.map(c=>({id:c.type,title:`${r.domain} ${c.type}`,...pe(c,n)}))??[],tabs:ss(t).map(c=>({id:c.id,label:n(c.titleKey)}))}}function us(r,t,e,s,i,n){const l=e.toLowerCase();return{fields:[[n("dns.entries"),r?ne(r.total,i):"—"]],coverage:r?["positive","negative","persistent"].filter(c=>!r.coverage[c]).map(c=>({id:c,text:n("ui.valuePair",{label:n({positive:"dns.positive",negative:"dns.negative",persistent:"dns.persistent"}[c]),value:n("dns.notCovered")})})):[],filterText:l?n("dns.cacheFilter",{domain:e}):"",confirmationText:r?n("dns.flushConfirm",{n:r.total}):n("dns.flushConfirmAll"),flushDisabled:!!s||!t?.dns_cache.available||!t.dns_cache.flush,empty:n(t?.dns_cache.available&&t.dns_cache.read?"dns.empty":"dns.cacheUnavailable"),rows:(r?.entries??[]).filter(c=>!l||c.domain.toLowerCase().includes(l)).map(c=>({id:c.entry_id,domain:c.domain,type:c.type,status:c.status,expiresAt:c.expires_at,staleUntil:c.stale_until,deleteLabel:n("dns.deleteEntry",{domain:c.domain,type:c.type}),pending:s===c.entry_id,disabled:!!s||!t?.dns_cache.available||!t.dns_cache.delete_entry}))}}function ms(r,t,e,s){const i=r?.records.find(l=>l.id===t);if(!i)return null;const n=pe(i,s);return{id:i.id,title:i.question.name,answers:n.answers,fields:[[s("ui.type"),i.question.type],[s("ui.device"),i.src??"—"],n.fields[0],[s("ui.cache"),n.cacheText],...n.fields.slice(1),[s("ui.time"),Ce(i.observed_at,e)]]}}function ps(r,t,e,s=[]){const i=r?.records??[];return{choices:[{id:"all",label:e("dns.allTypes")},...[...new Set([...s,...i.map(n=>n.question.type)])].map(n=>({id:n,label:n}))],total:r?e("dns.logTotal",{n:r.total}):"",loaded:r?.next_cursor?e("dns.logLoaded",{n:i.length}):"",empty:e(t===void 0?"ui.loading":t?"dns.logEmpty":"dns.logUnavailable"),rows:i.map(n=>({id:n.id,observedAt:n.observed_at,name:n.question.name,type:n.question.type,source:n.src??"—",resultError:n.status!=="NOERROR",result:n.status!=="NOERROR"?n.status:n.answers.map(l=>l.data).join(", ")||"—",cached:n.cached,upstream:n.cached?e("dns.hit"):n.upstream??"—",elapsed:j(n.elapsed_ms,e)}))}}function hs(r){return[ae(["id","observed_at","src","name","type","status","cached","upstream","route_source","route_rule","elapsed_ms","answers"]),...r.map(t=>ae([t.id,t.observed_at,t.src,t.question.name,t.question.type,t.status,t.cached?"true":"false",t.upstream,t.route.source,t.route.rule,t.elapsed_ms,t.answers.map(e=>e.data).join(" ")]))].join(`
-`)+`
-`}function xs(r,t){const e=new Set(r.records.map(s=>s.id));return{...r,records:[...r.records,...t.records.filter(s=>!e.has(s.id))],next_cursor:t.next_cursor}}function fs(r,t){const e=t&&new Set(t.records.map(s=>s.id));return{data:t??r,newerWaiting:!!e&&!!r?.records.some(s=>!e.has(s.id))}}function gs(r,t,e){if(!r)return null;const{usage:s,coverage:i}=r,n=c=>{const o=Se(c);return o===null?"—":ne(o,t)},l=s?Te(s.entries,s.entry_capacity):null;return{note:s?void 0:e("dns.chart.cacheNote",{n:r.total}),usage:s&&l!==null?{pct:l,value:l>0&&l<.5?"<"+e("ui.percent",{n:1}):e("ui.percent",{n:Math.round(l)}),facts:e("dns.chart.usageFacts",{entries:e("ui.fraction",{part:n(s.entries),whole:n(s.entry_capacity)})})}:null,coverage:e("dns.chart.coverage",{kinds:[i.positive&&e("dns.chart.positive"),i.negative&&e("dns.chart.negative")].filter(Boolean).join(e("ui.listSeparator")),persistent:e(i.persistent?"dns.chart.persistent":"dns.chart.memoryOnly")})}}function bs(r,t,e){return r?e instanceof _e&&e.status===503?"unavailable":t?"ready":e?"error":"loading":"unlisted"}function vs({go:r,query:t}){const e=g(),s=re(),i=V(),n=m.useMemo(()=>new URLSearchParams(t),[t]),[l,c]=m.useState(n.get("domain")??""),[o,u]=m.useState(n.get("type")??"A");q(n.get("domain"),p=>c(p??"")),q(n.get("type"),p=>u(p??"A"));const[h,x]=m.useState(null),{busy:y,error:d,run:v}=le({rethrow:!0}),f=i.data?.resources,w=m.useMemo(()=>ds(h,f,o,l,!!y,e),[h,f,o,l,y,e]),N=n.has("domain")&&w.tabs.some(p=>p.id==="log")?"log":w.tabs[0]?.id??"query",A=async()=>{try{await v("query",async p=>{const _=await Xe(s.dnsQuery,l.trim(),o==="all"?w.types:[o],f?.dns_query.limits?.max_types_per_request??1,p);return p.aborted||x(_),_})}catch{}};return{...w,domain:l,setDomain:c,type:o,setType:u,pending:y==="query",queryError:d,submit:()=>void A(),setTab:p=>r("dns",Le(t,p,f&&!n.has("domain")?N:null)),tab:De(t,w.tabs.map(p=>p.id),N),filterDomain:n.get("domain")??"",logEnabled:f?.dns_log.available,viewCache:()=>r("dns",Y(t,{tab:"cache",domain:h?.domain??""})),clearCacheFilter:()=>r("dns",Y(t,{tab:"cache",domain:null}))}}function js(r){const t=g(),e=$[I()],s=Ge(!qe()),i=m.useMemo(()=>us(s.cache.data,s.capabilities.data?.resources,r,s.busy,e,t),[s.cache.data,s.capabilities.data,r,s.busy,e,t]),{remove:n}=s,l=m.useCallback(o=>void n(o).then(u=>u&&O("positive",t("dns.deleted",{n:u.deleted})),u=>O("negative",t("dns.deleteFailed"),{detail:B(u,t)})),[n,t]),c=async()=>{try{const o=await s.flush();o&&O("positive",t("dns.flushed",{matched:o.matched,deleted:o.deleted}))}catch(o){return t("dns.flushFailed",{error:B(o,t)})}};return{...i,error:s.cache.error,retry:s.cache.refetch,loading:(s.cache.loading||s.capabilities.loading)&&!s.cache.data,flushPending:s.busy==="flush",remove:l,flush:c,abortFlush:()=>{s.cancel(),s.cache.refetch()}}}function ys(r){const t=me({},r===!0),e=V().data?.resources;return{log:t,cacheListed:Fe(e,"dns_cache",{whileLoading:!1})&&e?.dns_cache.read===!0}}function ws(r){const t=g(),e=$[I()],[s,i]=Me(),[n,l]=m.useState(!1),c=Ye(r,!i&&n);c.data&&!n&&l(!0);const o=m.useMemo(()=>gs(c.data,e,t),[c.data,e,t]);return{ref:s,card:o,state:bs(r,!!o,c.error),error:c.error,retry:c.refetch}}function Ns(r,t){const e=g(),s=$[I()],[i,n]=m.useState(t);q(t,n);const[l,c]=m.useState("all"),[o,u]=m.useState(""),h=re(),x=V(),y=Z(o),d=Re(y),v=y.trim()!==""&&!d,[f,w]=m.useState(d);!v&&d!==f&&w(d);const N={name:Z(i),type:l,src:v?f:d},A=JSON.stringify(N),p=me(N,r===!0),[_,E]=m.useState(null),[he,K]=m.useState(!1),S=le({scope:A});q(A,()=>E(null));const{data:b,newerWaiting:xe}=m.useMemo(()=>fs(p.data,_),[p.data,_]),X=()=>void S.run("older",async T=>{if(!b?.next_cursor)return;E(b);const{page:ve}=await Je(je=>h.dnsLog(je,T),{name:N.name.trim()||void 0,type:l==="all"?void 0:l,src:N.src,cursor:b.next_cursor,limit:p.limit},T);T.aborted||E(xs(b,ve))}),G=()=>{S.cancel(),E(null);const T=p.refetch();T&&(K(!0),T.finally(()=>K(!1)))},[M,fe]=m.useState(null),ge=Ae(Ee),J=x.data?.resources.dns_query.record_types,be=m.useMemo(()=>ps(b,r,e,J),[b,r,e,J]),k=m.useMemo(()=>ms(b,M,s,e),[b,M,s,e]);return{...be,detail:k,detailTitle:k?.title??"",name:i,newerWaiting:xe,setName:n,type:l,setType:c,src:o,setSrc:u,srcError:v?e("dns.srcInvalid"):void 0,selected:k?M:null,setSelected:fe,wide:ge,error:S.error??p.error,loading:p.loading&&!b,hasOlder:!!b?.next_cursor,loadingOlder:!!S.busy,loadOlder:X,refreshing:he,refresh:G,retry:S.error?X:G,export:()=>Ze(es("dns-log","csv"),hs(b?.records??[]),"text/csv;charset=utf-8")}}const Cs=["cached","answered","nxdomain","failed"],Ts=r=>r.cached?"cached":r.status==="NOERROR"?"answered":r.status==="NXDOMAIN"?"nxdomain":"failed";function _s(r){const t={cached:0,answered:0,nxdomain:0,failed:0},e=[];for(const c of r){const o=Ts(c);t[o]++,!c.cached&&c.upstream!==null&&e.push({id:c.id,value:c.elapsed_ms,outcome:o,name:c.question.name,upstream:c.upstream})}const s=e.map(c=>c.value).sort((c,o)=>c-o),i=new Map;for(const c of e)i.set(c.upstream,[...i.get(c.upstream)??[],c]);const n=[...i].map(([c,o])=>({upstream:c,median:P(o.map(u=>u.value).sort((u,h)=>u-h),50),samples:o}));n.sort((c,o)=>o.samples.length-c.samples.length||ke(c.upstream,o.upstream));const l=r.length-t.cached;return{domains:te(r.map(c=>c.question.name.replace(/\.$/,"")),8),devices:te(r.map(c=>c.src===null?null:Ss(c.src)),8),total:r.length,counts:t,uncached:l,samples:e,typical:P(s,50),slowest:P(s,95),failureRate:l?t.failed/l:null,cacheRate:r.length?t.cached/r.length:null,upstreams:n}}const Ss=r=>r.replace(/:\d+$/,""),Ds=(r,t)=>!!r?.next_cursor&&t!==void 0&&r.records.length_s(r),[r]),c={cached:n.positive,answered:n.cat[2],nxdomain:n.notice,failed:n.negative},o=d=>i("ui.percent",{n:d===null?0:Math.round(d*100)}),u=(d,v)=>{const f=v?d/v:0;return d>0&&f<.005?"<"+i("ui.percent",{n:1}):d.995?">"+i("ui.percent",{n:99}):o(f)},h=d=>({id:d.id,value:d.value,color:c[d.outcome],lines:[d.name,j(d.value,i),i(W[d.outcome])]}),x=t??(l.total<5?a.jsx(C,{children:i("dns.chart.tooFew")}):null),y=[{label:i("dns.chart.median"),value:j(l.typical,i),icon:a.jsx(Oe,{}),tint:"c1"},{label:i("dns.chart.p95"),value:j(l.slowest,i),icon:a.jsx(Pe,{}),tint:"c4"},{label:i("dns.chart.cacheRate"),value:o(l.cacheRate),icon:a.jsx(We,{}),tint:"c2"},{label:i("dns.chart.failureRate"),value:o(l.failureRate),icon:a.jsx(Be,{}),tint:"c5",tone:l.counts.failed?"negative":void 0}];return a.jsxs("div",{className:"rp-chart-page",children:[e,!x&&a.jsx(as,{facts:y}),a.jsxs("div",{className:"rp-g21",children:[a.jsx(L,{title:i("dns.chart.speed",{n:l.samples.length}),note:x?void 0:i("dns.chart.sample",{n:l.total,uncached:l.uncached,upstream:l.samples.length}),children:x??a.jsxs(a.Fragment,{children:[a.jsx(ts,{label:i("dns.chart.speed",{n:l.samples.length}),points:l.samples.map(h),marks:l.typical!==null&&l.slowest!==null?[{value:l.typical,label:i("dns.chart.typical",{value:j(l.typical,i)})},{value:l.slowest,label:i("dns.chart.slowest",{value:j(l.slowest,i)})}]:[],rows:l.upstreams.map(d=>({id:d.upstream,label:d.upstream,detail:i("dns.chart.upstream",{n:d.samples.length,median:j(d.median,i)}),points:d.samples.map(h),mark:d.median})),fmt:d=>j(d,i)}),a.jsxs("div",{className:"rp-legend",children:[["answered","nxdomain","failed"].map(d=>a.jsx(ee,{swatch:c[d],label:i(W[d])},d)),a.jsx(ee,{swatch:a.jsx("i",{className:"rp-median-key","aria-hidden":"true"}),label:i("dns.chart.medianKey")})]})]})}),a.jsx(L,{title:i("dns.chart.outcomes"),children:x??a.jsx(is,{label:i("dns.chart.outcomes"),shares:Cs.map(d=>({id:d,label:i(W[d]),count:l.counts[d],color:c[d],text:i("dns.chart.share",{n:l.counts[d],share:u(l.counts[d],l.total)})}))})})]}),a.jsxs("div",{className:"rp-g21",children:[a.jsx(qs,{analysis:l,standIn:x}),a.jsx(Es,{listed:s})]})]})}function Es({listed:r}){const t=g(),e=Q(),{ref:s,...i}=ws(r);return a.jsx(L,{ref:s,title:t("dns.chart.cache"),note:i.state==="ready"?i.card?.note:void 0,children:i.state==="unlisted"?a.jsx(C,{children:t("dns.cacheUnavailable")}):i.state==="unavailable"?a.jsx(C,{children:t("dns.cacheBusy")}):i.state==="error"?a.jsx(R,{error:i.error,onRetry:i.retry}):i.card?a.jsxs(a.Fragment,{children:[i.card.usage&&a.jsxs("div",{className:"rp-form",children:[a.jsx(ce,{label:t("dns.chart.usage"),value:i.card.usage.value,pct:i.card.usage.pct,color:e.accent}),a.jsx("span",{className:"rp-label",children:i.card.usage.facts})]}),a.jsx("p",{className:"rp-note",children:i.card.coverage})]}):a.jsx(ie,{})})}function qs({analysis:r,standIn:t}){const e=g(),s=Q(),[i,n]=m.useState("device"),l=i==="device"?r.devices:r.domains,c=l.top[0]?.count??1;return a.jsx(L,{title:e("dns.chart.ranking"),aside:!t&&a.jsx(Ue,{label:e("dns.chart.ranking"),value:i,onChange:n,items:[["device",e("dns.chart.byDevice")],["domain",e("dns.chart.byDomain")]]}),children:t??a.jsxs(a.Fragment,{children:[a.jsx("div",{className:"rp-list",children:l.top.map(o=>a.jsx(ce,{label:o.key??e("dns.chart.resolver"),value:e("dns.chart.count",{n:o.count}),pct:o.count/c*100,color:i==="device"?s.cat[0]:s.cat[3]},o.key??""))}),l.rest>0&&a.jsx("p",{className:"rp-note",children:e("dns.chart.rest",{n:l.rest})})]})})}function Gs(r){const t=g(),e=vs(r),s=a.jsxs(a.Fragment,{children:[e.queryError&&a.jsx(R,{error:e.queryError,onRetry:e.submit,message:t("dns.queryFailed",{error:B(e.queryError,t)})}),a.jsx("form",{className:He(),onSubmit:n=>{n.preventDefault(),e.submit()},children:a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(U,{side:!0,label:t("ui.domain"),value:e.domain,onChange:e.setDomain,width:280,placeholder:"example.com"}),a.jsx(oe,{label:t("ui.type"),side:!0,value:e.type,onChange:e.setType,items:e.choices}),a.jsx(F,{accent:!0,type:"submit",isPending:e.pending,isDisabled:e.disabled,children:t("dns.query")})]})}),e.cards.length>0&&a.jsx("div",{className:"rp-col",children:e.cards.map(n=>a.jsxs(L,{className:"rp-col",children:[a.jsxs("div",{className:"rp-row",children:[a.jsxs("div",{className:"rp-cluster",children:[a.jsx("h3",{className:"rp-h3",children:n.title}),a.jsx(de,{tone:n.cacheTone,children:n.cacheText})]}),e.showCache&&a.jsx(F,{quiet:!0,small:!0,onPress:e.viewCache,children:t("dns.viewCache")})]}),a.jsx(z,{inline:!0,items:n.fields}),n.answers.length?a.jsx("div",{className:"rp-list",children:n.answers.map((l,c)=>a.jsx("div",{className:"rp-code",children:l},c))}):a.jsx(C,{children:t("dns.noAnswers")})]},n.id))})]}),i={stats:a.jsx(Ls,{enabled:e.logEnabled}),query:s,cache:a.jsx(Fs,{domain:e.filterDomain,clearFilter:e.clearCacheFilter}),log:a.jsx(Ms,{enabled:e.logEnabled,initialName:e.filterDomain})};return a.jsx("div",{className:"rp-page",children:a.jsx(Ve,{keepMounted:!0,label:t("nav.dns"),items:e.tabs.map(n=>({...n,content:i[n.id]})),value:e.tab,onChange:e.setTab})})}function Fs({domain:r,clearFilter:t}){const e=g(),s=js(r),{remove:i}=s,n=m.useMemo(()=>[{id:"q",label:e("ui.domain"),minWidth:192,isRowHeader:!0,render:l=>a.jsx(D,{className:"rp-code",text:l.id,children:l.domain})},{id:"t",label:e("ui.type"),minWidth:64,grow:0,drop:3,render:l=>l.type},{id:"s",label:e("ui.state"),minWidth:104,grow:0,render:l=>l.status},{id:"e",label:e("dns.expires"),minWidth:96,drop:2,render:l=>a.jsx(H,{at:l.expiresAt})},{id:"st",label:e("dns.staleUntil"),minWidth:104,drop:1,render:l=>a.jsx(H,{at:l.staleUntil})},{id:"a",label:e("ui.delete"),minWidth:80,grow:0,render:l=>a.jsx(F,{quiet:!0,icon:!0,small:!0,label:l.deleteLabel,isPending:l.pending,isDisabled:l.disabled,onPress:()=>i(l.id),children:a.jsx(cs,{})})}],[e,i]);return a.jsxs(a.Fragment,{children:[s.error&&a.jsx(R,{error:s.error,onRetry:s.retry}),a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(z,{row:!0,items:s.fields}),s.coverage.map(l=>a.jsx(de,{tone:"warn",children:l.text},l.id)),s.filterText&&a.jsx(F,{small:!0,onPress:t,children:s.filterText}),a.jsx("span",{className:"rp-grow"}),a.jsx(ze,{label:e("dns.flushAll"),confirmationText:s.confirmationText,isPending:s.flushPending,isDisabled:s.flushPending||s.flushDisabled,onConfirm:s.flush,onAbort:s.abortFlush})]}),a.jsx(ue,{label:e("ui.cache"),height:442,fit:!0,rows:s.rows,loading:s.loading,empty:s.empty,cols:n})]})}function Ms({enabled:r,initialName:t}){const e=g(),s=Ns(r,t),i=m.useMemo(()=>[{id:"t",label:e("ui.time"),minWidth:96,grow:0,render:n=>a.jsx(H,{at:n.observedAt})},{id:"q",label:e("ui.domain"),minWidth:200,grow:2,isRowHeader:!0,render:n=>a.jsx(D,{children:n.name})},{id:"ty",label:e("ui.type"),minWidth:64,grow:0,drop:3,render:n=>n.type},{id:"s",label:e("ui.device"),minWidth:128,drop:2,render:n=>a.jsx(D,{className:"rp-code",children:n.source})},{id:"r",label:e("dns.result"),minWidth:160,grow:2,render:n=>n.resultError?a.jsx(se,{small:!0,tone:"err",children:n.result}):a.jsx(D,{className:"rp-code",children:n.result})},{id:"u",label:e("ui.upstream"),minWidth:128,drop:1,render:n=>n.cached?a.jsx(se,{small:!0,tone:"ok",children:n.upstream}):a.jsx(D,{children:n.upstream})},{id:"e",label:e("ui.elapsed"),minWidth:72,grow:0,align:"end",drop:4,render:n=>n.elapsed}],[e]);return a.jsxs(a.Fragment,{children:[a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(U,{search:!0,label:e("ui.domain"),value:s.name,onChange:s.setName,placeholder:e("dns.logFilterHint"),width:240}),a.jsx(oe,{label:e("ui.type"),side:!0,value:s.type,onChange:s.setType,items:s.choices}),a.jsx(U,{search:!0,label:e("ui.device"),value:s.src,onChange:s.setSrc,isInvalid:!!s.srcError,placeholder:"10.0.0.12",width:160}),s.total&&a.jsx("span",{className:"rp-label",children:s.total}),s.loaded&&a.jsx("span",{className:"rp-label",children:s.loaded}),a.jsx("span",{className:"rp-grow"}),a.jsx(Ke,{actions:[{id:"export",label:e("dns.exportLog"),icon:a.jsx($e,{}),isDisabled:!s.rows.length,onAction:s.export},{id:"refresh",label:e("refresh"),icon:a.jsx(Ie,{className:"rp-spin-on-press"}),isPending:s.refreshing,onAction:s.refresh},...s.hasOlder?[{id:"older",label:e("dns.loadOlder"),isPending:s.loadingOlder,onAction:s.loadOlder}]:[]]})]}),s.error&&a.jsx(R,{error:s.error,onRetry:s.retry}),s.srcError&&a.jsx("p",{className:"rp-note",children:s.srcError}),s.newerWaiting&&a.jsx("p",{className:"rp-note",children:e("dns.newerWaiting")}),a.jsxs("div",{className:"rp-with-panel","data-open":s.detail?"":void 0,children:[a.jsx(ue,{label:e("dns.log"),rowDetail:!0,height:520,rows:s.rows,selected:s.selected,onSelect:s.setSelected,selectOnFocus:s.wide,loading:s.loading,empty:s.empty,cols:i}),a.jsx(Qe,{open:!!s.detail,title:s.detailTitle,onClose:()=>s.setSelected(null),children:s.detail&&a.jsxs(a.Fragment,{children:[a.jsx(z,{inline:!0,items:s.detail.fields}),s.detail.answers.length?a.jsx("div",{className:"rp-list",children:s.detail.answers.map((n,l)=>a.jsx("div",{className:"rp-code",children:n},l))}):a.jsx(C,{children:e("dns.noAnswers")})]})})]})]})}export{Gs as Dns};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Dns-vjK8rYCH.js b/luci-app-honk/root/etc/honk/dashboard/assets/Dns-vjK8rYCH.js
new file mode 100644
index 000000000..40913bee1
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Dns-vjK8rYCH.js
@@ -0,0 +1,3 @@
+import{r as p,j as a}from"./vendor-react-Bf71BWbF.js";import{u as g,aM as we,c as Ne,a0 as Ce,aT as j,aq as Te,a1 as re,ak as _e,A as Se,au as De,bo as le,a5 as V,bc as F,bp as ie,X as Y,bf as Re,be as Le,a2 as $,a as I,bq as Z,U as qe,f as Ae,bi as Fe,br as Ee,bb as k,b as ee,a7 as Me,bs as Oe,aP as ke,af as C,j as oe,E as L,aB as Q,bt as Pe,bu as We,bv as Ue,bw as He,aG as R,aO as se,aI as ce,b1 as Be,bx as U,T as H,b2 as de,B as E,by as Ve,aH as ue,aD as z,bn as $e,aE as D,aC as ae,bm as Ie,aF as Qe,bz as ze,bl as Ke,bk as Ge}from"./index-CXHBmSa5.js";import{D as pe}from"./Table-D0NFHHNQ.js";import{T as B}from"./TimeCell-gSIuLEFc.js";import{A as Xe}from"./ActionGroup-90AzAQje.js";import{q as Je,u as he,a as Ye,s as Ze,b as es}from"./dns-DQrpG8y_.js";import{c as te,d as ss,e as as}from"./files-BxEOxSF8.js";import{d as ts}from"./nav-C2A1sZKm.js";import{F as ns}from"./FactStrip-BgQ_tYB6.js";import{r as ne,B as rs}from"./ranked-FVqORIQj.js";import{u as ls,w as is,C as os,p as P}from"./layout-BRLew_nj.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";function cs({label:r,shares:t}){const e=g(),s=we(),{ref:l,tip:n,show:i,hide:o}=ls(),c=p.useMemo(()=>{const d=is(t.map(m=>m.count));return t.flatMap((m,f)=>Array.from({length:d[f]},()=>m))},[t]);return a.jsxs("div",{className:"rp-waffle rp-chart-hover",ref:l,onPointerLeave:o,children:[a.jsx("div",{className:"grid",role:"img","aria-describedby":s,"aria-label":e("ui.valuePair",{label:r,value:t.map(d=>`${d.label} ${d.text}`).join(e("ui.separator"))}),children:c.map((d,m)=>a.jsx("span",{style:{background:d.color},onPointerMove:f=>i(f,[d.label,d.text])},m))}),a.jsx("ul",{className:"legend",children:t.map(d=>a.jsxs("li",{children:[a.jsx("i",{className:"sw",style:{background:d.color}}),a.jsx("span",{children:d.label}),a.jsx("b",{children:d.text})]},d.id))}),a.jsx(os,{tip:n})]})}function ds({className:r,...t}){return a.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:20,height:20,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:Ne("rp-icon",r),...t,children:[a.jsx("path",{fill:"currentColor",d:"M8.249 15.021c-.4 0-.733-.317-.748-.72l-.25-6.5c-.017-.414.307-.763.72-.779H8c.4 0 .733.317.748.72l.25 6.5c.017.414-.307.763-.72.778zM11.751 15.021h-.03c-.413-.016-.737-.365-.72-.779l.25-6.5c.015-.403.348-.72.748-.72h.03c.413.016.737.365.72.779l-.25 6.5c-.015.403-.348.72-.748.72"}),a.jsx("path",{fill:"currentColor",d:"M17 4h-3.5v-.75C13.5 2.01 12.49 1 11.25 1h-2.5C7.51 1 6.5 2.01 6.5 3.25V4H3c-.414 0-.75.336-.75.75s.336.75.75.75h.52l.422 10.342C3.99 17.052 4.98 18 6.19 18h7.62c1.211 0 2.2-.948 2.248-2.158L16.48 5.5H17c.414 0 .75-.336.75-.75S17.414 4 17 4m-9-.75c0-.413.337-.75.75-.75h2.5c.413 0 .75.337.75.75V4H8zm6.56 12.531c-.017.404-.346.719-.75.719H6.19c-.404 0-.733-.315-.75-.719L5.02 5.5h9.96z"})]})}const us={forced:"dns.route.forced","dns.routing":"dns.route.rules",default:"dns.route.default"};function me(r,t){return{fields:[[t("ui.state"),r.status],[t("ui.upstream"),r.upstream??"—"],[t("dns.routeSource"),Ce(us,r.route.source,t)],[t("dns.routeRule"),r.route.rule??"—"],[t("ui.elapsed"),j(r.elapsed_ms,t)]],answers:(r.answers??[]).map(e=>t("dns.answer",{name:e.name,type:e.type,ttl:e.ttl,data:e.data})),cacheText:t(r.cached?"dns.hit":"dns.miss"),cacheTone:r.cached?void 0:"warn"}}function ps(r,t,e,s,l,n){const i=t?.dns_query.record_types??[],o=e==="all"?i.length>0:i.includes(e);return{types:i,choices:[...i.map(c=>({id:c,label:c})),{id:"all",label:n("dns.allTypes")}],disabled:l||!t?.dns_query.available||!o||!s.trim(),reason:!t||l?null:t.dns_query.available?o?null:n(e==="all"?"dns.noTypes":"dns.typeUnsupported"):n("dns.queryUnavailable"),showCache:!!t?.dns_cache.available,cards:r?.results.map(c=>({id:c.type,title:`${r.domain} ${c.type}`,...me(c,n)}))??[],tabs:ts(t).map(c=>({id:c.id,label:n(c.titleKey)}))}}function hs(r,t,e,s,l,n){const i=e.toLowerCase(),o=t?.dns_cache,c=(r?.entries??[]).filter(d=>!i||d.domain.toLowerCase().includes(i));return{fields:[[n("dns.entries"),r?re(r.total,l):"—"]],coverage:r?["positive","negative","persistent"].filter(d=>!r.coverage[d]).map(d=>({id:d,text:n("ui.valuePair",{label:n({positive:"dns.positive",negative:"dns.negative",persistent:"dns.persistent"}[d]),value:n(d==="persistent"?"dns.chart.memoryOnly":"dns.notCovered")})})):[],filterText:i?n("dns.cacheFilter",{domain:e}):"",confirmationText:r?n("dns.flushConfirm",{n:r.total}):n("dns.flushConfirmAll"),flushDisabled:!!s||!t?.dns_cache.available||!t.dns_cache.flush,flushReason:o&&!s&&(!o.available||!o.flush)?n("dns.flushUnsupported"):null,deleteReason:o&&!s&&c.length>0&&(!o.available||!o.delete_entry)?n("dns.deleteUnsupported"):null,empty:n(t?.dns_cache.available&&t.dns_cache.read?"dns.empty":"dns.cacheUnavailable"),rows:c.map(d=>({id:d.entry_id,domain:d.domain,type:d.type,status:d.status,expiresAt:d.expires_at,staleUntil:d.stale_until,deleteLabel:n("dns.deleteEntry",{domain:d.domain,type:d.type}),pending:s===d.entry_id,disabled:!!s||!t?.dns_cache.available||!t.dns_cache.delete_entry}))}}function ms(r,t,e,s){const l=r?.records.find(i=>i.id===t);if(!l)return null;const n=me(l,s);return{id:l.id,title:l.question.name,answers:n.answers,fields:[[s("ui.type"),l.question.type],[s("ui.device"),l.src??"—"],n.fields[0],[s("ui.cache"),n.cacheText],...n.fields.slice(1),[s("ui.time"),Te(l.observed_at,e)]]}}function fs(r,t,e,s=[]){const l=r?.records??[];return{choices:[{id:"all",label:e("dns.allTypes")},...[...new Set([...s,...l.map(n=>n.question.type)])].map(n=>({id:n,label:n}))],total:r?e("dns.logTotal",{n:r.total}):"",totalHelp:r?{title:e("dns.logTotal",{n:r.total}),text:e("dns.logTotalHelp")}:null,loaded:r?.next_cursor?e("dns.logLoaded",{n:l.length}):"",empty:e(t===void 0?"ui.loading":t?"dns.logEmpty":"dns.logUnavailable"),rows:l.map(n=>({id:n.id,observedAt:n.observed_at,name:n.question.name,type:n.question.type,source:n.src??"—",resultError:n.status!=="NOERROR",result:n.status!=="NOERROR"?n.status:n.answers.map(i=>i.data).join(", ")||"—",cached:n.cached,upstream:n.cached?e("dns.hit"):n.upstream??"—",elapsed:j(n.elapsed_ms,e)}))}}function xs(r){return[te(["id","observed_at","src","name","type","status","cached","upstream","route_source","route_rule","elapsed_ms","answers"]),...r.map(t=>te([t.id,t.observed_at,t.src,t.question.name,t.question.type,t.status,t.cached?"true":"false",t.upstream,t.route.source,t.route.rule,t.elapsed_ms,t.answers.map(e=>e.data).join(" ")]))].join(`
+`)+`
+`}function gs(r,t){const e=new Set(r.records.map(s=>s.id));return{...r,records:[...r.records,...t.records.filter(s=>!e.has(s.id))],next_cursor:t.next_cursor}}function bs(r,t){const e=t&&new Set(t.records.map(s=>s.id));return{data:t??r,newerWaiting:!!e&&!!r?.records.some(s=>!e.has(s.id))}}function vs(r,t,e){if(!r)return null;const{usage:s,coverage:l}=r,n=o=>{const c=De(o);return c===null?"—":re(c,t)},i=s?_e(s.entries,s.entry_capacity):null;return{note:s?void 0:e("dns.chart.cacheNote",{n:r.total}),usage:s&&i!==null?{pct:i,value:i>0&&i<.5?"<"+e("ui.percent",{n:1}):e("ui.percent",{n:Math.round(i)}),facts:e("dns.chart.usageFacts",{entries:e("ui.fraction",{part:n(s.entries),whole:n(s.entry_capacity)})})}:null,coverage:e("dns.chart.coverage",{kinds:[l.positive&&e("dns.chart.positive"),l.negative&&e("dns.chart.negative")].filter(Boolean).join(e("ui.listSeparator")),persistent:e(l.persistent?"dns.chart.persistent":"dns.chart.memoryOnly")})}}function js(r,t,e){return r?e instanceof Se&&e.status===503?"unavailable":t?"ready":e?"error":"loading":"unlisted"}function ys({go:r,query:t}){const e=g(),s=le(),l=V(),n=p.useMemo(()=>new URLSearchParams(t),[t]),[i,o]=p.useState(n.get("domain")??""),[c,d]=p.useState(n.get("type")??"A");F(n.get("domain"),h=>o(h??"")),F(n.get("type"),h=>d(h??"A"));const[m,f]=p.useState(null),{busy:y,error:u,run:v}=ie({rethrow:!0}),x=l.data?.resources,w=p.useMemo(()=>ps(m,x,c,i,!!y,e),[m,x,c,i,y,e]),N=n.has("domain")&&w.tabs.some(h=>h.id==="log")?"log":w.tabs[0]?.id??"query",q=async()=>{try{await v("query",async h=>{const _=await Je(s.dnsQuery,i.trim(),c==="all"?w.types:[c],x?.dns_query.limits?.max_types_per_request??1,h);return h.aborted||f(_),_})}catch{}};return{...w,domain:i,setDomain:o,type:c,setType:d,pending:y==="query",queryError:u,submit:()=>void q(),setTab:h=>r("dns",Le(t,h,x&&!n.has("domain")?N:null)),tab:Re(t,w.tabs.map(h=>h.id),N),filterDomain:n.get("domain")??"",logEnabled:x?.dns_log.available,viewCache:()=>r("dns",Y(t,{tab:"cache",domain:m?.domain??""})),clearCacheFilter:()=>r("dns",Y(t,{tab:"cache",domain:null}))}}function ws(r){const t=g(),e=$[I()],s=Ye(!Ee()),l=p.useMemo(()=>hs(s.cache.data,s.capabilities.data?.resources,r,s.busy,e,t),[s.cache.data,s.capabilities.data,r,s.busy,e,t]),{remove:n}=s,i=p.useCallback(c=>void n(c).then(d=>d&&k("positive",t("dns.deleted",{n:d.deleted})),d=>k("negative",t("dns.deleteFailed"),{detail:ee(d,t)})),[n,t]),o=async()=>{try{const c=await s.flush();c&&k("positive",t("dns.flushed",{matched:c.matched,deleted:c.deleted}))}catch(c){return t("dns.flushFailed",{error:ee(c,t)})}};return{...l,error:s.cache.error,retry:s.cache.refetch,loading:(s.cache.loading||s.capabilities.loading)&&!s.cache.data,flushPending:s.busy==="flush",remove:i,flush:o,abortFlush:()=>{s.cancel(),s.cache.refetch()}}}function Ns(r){const t=he({},r===!0),e=V().data?.resources;return{log:t,cacheListed:Me(e,"dns_cache",{whileLoading:!1})&&e?.dns_cache.read===!0}}function Cs(r){const t=g(),e=$[I()],[s,l]=Oe(),[n,i]=p.useState(!1),o=es(r,!l&&n);o.data&&!n&&i(!0);const c=p.useMemo(()=>vs(o.data,e,t),[o.data,e,t]);return{ref:s,card:c,state:js(r,!!c,o.error),error:o.error,retry:o.refetch}}function Ts(r,t){const e=g(),s=$[I()],[l,n]=p.useState(t);F(t,n);const[i,o]=p.useState("all"),[c,d]=p.useState(""),m=le(),f=V(),y=Z(c),u=qe(y),v=y.trim()!==""&&!u,[x,w]=p.useState(u);!v&&u!==x&&w(u);const N={name:Z(l),type:i,src:v?x:u},q=JSON.stringify(N),h=he(N,r===!0),[_,A]=p.useState(null),[fe,K]=p.useState(!1),S=ie({scope:q});F(q,()=>A(null));const{data:b,newerWaiting:xe}=p.useMemo(()=>bs(h.data,_),[h.data,_]),G=()=>void S.run("older",async T=>{if(!b?.next_cursor)return;A(b);const{page:je}=await Ze(ye=>m.dnsLog(ye,T),{name:N.name.trim()||void 0,type:i==="all"?void 0:i,src:N.src,cursor:b.next_cursor,limit:h.limit},T);T.aborted||A(gs(b,je))}),X=()=>{S.cancel(),A(null);const T=h.refetch();T&&(K(!0),T.finally(()=>K(!1)))},[M,ge]=p.useState(null),be=Ae(Fe),J=f.data?.resources.dns_query.record_types,ve=p.useMemo(()=>fs(b,r,e,J),[b,r,e,J]),O=p.useMemo(()=>ms(b,M,s,e),[b,M,s,e]);return{...ve,detail:O,detailTitle:O?.title??"",name:l,newerWaiting:xe,setName:n,type:i,setType:o,src:c,setSrc:d,srcError:v?e("ui.invalidIp"):void 0,selected:O?M:null,setSelected:ge,wide:be,error:S.error??h.error,loading:h.loading&&!b,hasOlder:!!b?.next_cursor,loadingOlder:!!S.busy,loadOlder:G,refreshing:fe,refresh:X,retry:S.error?G:X,export:()=>ss(as("dns-log","csv"),xs(b?.records??[]),"text/csv;charset=utf-8")}}const _s=["cached","answered","nxdomain","failed"],Ss=r=>r.cached?"cached":r.status==="NOERROR"?"answered":r.status==="NXDOMAIN"?"nxdomain":"failed";function Ds(r){const t={cached:0,answered:0,nxdomain:0,failed:0},e=[];for(const o of r){const c=Ss(o);t[c]++,!o.cached&&o.upstream!==null&&e.push({id:o.id,value:o.elapsed_ms,outcome:c,name:o.question.name,upstream:o.upstream})}const s=e.map(o=>o.value).sort((o,c)=>o-c),l=new Map;for(const o of e)l.set(o.upstream,[...l.get(o.upstream)??[],o]);const n=[...l].map(([o,c])=>({upstream:o,median:P(c.map(d=>d.value).sort((d,m)=>d-m),50),samples:c}));n.sort((o,c)=>c.samples.length-o.samples.length||ke(o.upstream,c.upstream));const i=r.length-t.cached;return{domains:ne(r.map(o=>o.question.name.replace(/\.$/,"")),8),devices:ne(r.map(o=>o.src===null?null:Rs(o.src)),8),total:r.length,counts:t,uncached:i,samples:e,typical:P(s,50),slowest:P(s,95),failureRate:i?t.failed/i:null,cacheRate:r.length?t.cached/r.length:null,upstreams:n}}const Rs=r=>r.replace(/:\d+$/,""),Ls=(r,t)=>!!r?.next_cursor&&t!==void 0&&r.records.lengthDs(r),[r]),o={cached:n.positive,answered:n.cat[2],nxdomain:n.notice,failed:n.negative},c=u=>l("ui.percent",{n:u===null?0:Math.round(u*100)}),d=(u,v)=>{const x=v?u/v:0;return u>0&&x<.005?"<"+l("ui.percent",{n:1}):u.995?">"+l("ui.percent",{n:99}):c(x)},m=u=>({id:u.id,value:u.value,color:o[u.outcome],lines:[u.name,j(u.value,l),l(W[u.outcome])]}),f=t??(i.total<5?a.jsx(C,{children:l("dns.chart.tooFew")}):null),y=[{label:l("dns.chart.median"),value:j(i.typical,l),icon:a.jsx(Pe,{}),tint:"c1"},{label:l("dns.chart.p95"),value:j(i.slowest,l),icon:a.jsx(We,{}),tint:"c4"},{label:l("dns.chart.cacheRate"),value:c(i.cacheRate),icon:a.jsx(Ue,{}),tint:"c2"},{label:l("dns.chart.failureRate"),value:c(i.failureRate),icon:a.jsx(He,{}),tint:"c5",tone:i.counts.failed?"negative":void 0}];return a.jsxs("div",{className:"rp-chart-page",children:[e,!f&&a.jsx(ns,{facts:y}),a.jsxs("div",{className:"rp-g21",children:[a.jsx(R,{title:l("dns.chart.speed",{n:i.samples.length}),note:f?void 0:l("dns.chart.sample",{n:i.total,uncached:i.uncached,upstream:i.samples.length}),children:f??a.jsxs(a.Fragment,{children:[a.jsx(rs,{label:l("dns.chart.speed",{n:i.samples.length}),points:i.samples.map(m),marks:i.typical!==null&&i.slowest!==null?[{value:i.typical,label:l("dns.chart.typical",{value:j(i.typical,l)})},{value:i.slowest,label:l("dns.chart.slowest",{value:j(i.slowest,l)})}]:[],rows:i.upstreams.map(u=>({id:u.upstream,label:u.upstream,detail:l("dns.chart.upstream",{n:u.samples.length,median:j(u.median,l)}),points:u.samples.map(m),mark:u.median})),fmt:u=>j(u,l)}),a.jsxs("div",{className:"rp-legend",children:[["answered","nxdomain","failed"].map(u=>a.jsx(se,{swatch:o[u],label:l(W[u])},u)),a.jsx(se,{swatch:a.jsx("i",{className:"rp-median-key","aria-hidden":"true"}),label:l("dns.chart.medianKey")})]})]})}),a.jsx(R,{title:l("dns.chart.outcomes"),children:f??a.jsx(cs,{label:l("dns.chart.outcomes"),shares:_s.map(u=>({id:u,label:l(W[u]),count:i.counts[u],color:o[u],text:l("dns.chart.share",{n:i.counts[u],share:d(i.counts[u],i.total)})}))})})]}),a.jsxs("div",{className:"rp-g21",children:[a.jsx(Ms,{analysis:i,standIn:f}),a.jsx(Es,{listed:s})]})]})}function Es({listed:r}){const t=g(),e=Q(),{ref:s,...l}=Cs(r);return a.jsx(R,{ref:s,title:t("dns.chart.cache"),note:l.state==="ready"?l.card?.note:void 0,children:l.state==="unlisted"?a.jsx(C,{children:t("dns.cacheUnavailable")}):l.state==="unavailable"?a.jsx(C,{children:t("dns.cacheBusy")}):l.state==="error"?a.jsx(L,{error:l.error,onRetry:l.retry}):l.card?a.jsxs(a.Fragment,{children:[l.card.usage&&a.jsxs("div",{className:"rp-form",children:[a.jsx(ce,{label:t("dns.chart.usage"),value:l.card.usage.value,pct:l.card.usage.pct,color:e.accent}),a.jsx("span",{className:"rp-label",children:l.card.usage.facts})]}),a.jsx("p",{className:"rp-note",children:l.card.coverage})]}):a.jsx(oe,{})})}function Ms({analysis:r,standIn:t}){const e=g(),s=Q(),[l,n]=p.useState("device"),i=l==="device"?r.devices:r.domains,o=i.top[0]?.count??1;return a.jsx(R,{title:e("dns.chart.ranking"),aside:!t&&a.jsx(Be,{label:e("dns.chart.ranking"),value:l,onChange:n,items:[["device",e("dns.chart.byDevice")],["domain",e("dns.chart.byDomain")]]}),children:t??a.jsxs(a.Fragment,{children:[a.jsx("div",{className:"rp-list",children:i.top.map(c=>a.jsx(ce,{label:c.key??e("dns.chart.resolver"),value:e("dns.chart.count",{n:c.count}),pct:c.count/o*100,color:l==="device"?s.cat[0]:s.cat[3]},c.key??""))}),i.rest>0&&a.jsx("p",{className:"rp-note",children:e("dns.chart.rest",{n:i.rest})})]})})}function Ys(r){const t=g(),e=ys(r),s=a.jsxs(a.Fragment,{children:[e.queryError&&a.jsx(L,{error:e.queryError,onRetry:e.submit,message:n=>t("dns.queryFailed",{error:n})}),a.jsx("form",{className:Ve(),onSubmit:n=>{n.preventDefault(),e.submit()},children:a.jsx(U,{reason:e.reason,children:a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(H,{side:!0,label:t("ui.domain"),value:e.domain,onChange:e.setDomain,width:280,placeholder:"example.com"}),a.jsx(de,{label:t("ui.type"),side:!0,value:e.type,onChange:e.setType,items:e.choices}),a.jsx(E,{accent:!0,type:"submit",isPending:e.pending,isDisabled:e.disabled,children:t("dns.query")})]})})}),e.cards.length>0&&a.jsx("div",{className:"rp-col",children:e.cards.map(n=>a.jsxs(R,{className:"rp-col",children:[a.jsxs("div",{className:"rp-row",children:[a.jsxs("div",{className:"rp-cluster",children:[a.jsx("h3",{className:"rp-h3",children:n.title}),a.jsx(ue,{tone:n.cacheTone,children:n.cacheText})]}),e.showCache&&a.jsx(E,{quiet:!0,small:!0,onPress:e.viewCache,children:t("dns.viewCache")})]}),a.jsx(z,{inline:!0,items:n.fields}),n.answers.length?a.jsx("div",{className:"rp-list",children:n.answers.map((i,o)=>a.jsx("div",{className:"rp-code",children:i},o))}):a.jsx(C,{children:t("dns.noAnswers")})]},n.id))})]}),l={stats:a.jsx(qs,{enabled:e.logEnabled}),query:s,cache:a.jsx(Os,{domain:e.filterDomain,clearFilter:e.clearCacheFilter}),log:a.jsx(ks,{enabled:e.logEnabled,initialName:e.filterDomain})};return a.jsx("div",{className:"rp-page",children:a.jsx($e,{keepMounted:!0,label:t("nav.dns"),items:e.tabs.map(n=>({...n,content:l[n.id]})),value:e.tab,onChange:e.setTab})})}function Os({domain:r,clearFilter:t}){const e=g(),s=ws(r),{remove:l}=s,n=p.useMemo(()=>[{id:"q",label:e("ui.domain"),minWidth:192,isRowHeader:!0,render:i=>a.jsx(D,{className:"rp-code",text:i.id,children:i.domain})},{id:"t",label:e("ui.type"),minWidth:64,grow:0,drop:3,render:i=>i.type},{id:"s",label:e("ui.state"),minWidth:104,grow:0,render:i=>i.status},{id:"e",label:e("dns.expires"),minWidth:96,drop:2,render:i=>a.jsx(B,{at:i.expiresAt})},{id:"st",label:e("dns.staleUntil"),minWidth:104,drop:1,render:i=>a.jsx(B,{at:i.staleUntil})},{id:"a",label:e("ui.delete"),minWidth:80,grow:0,render:i=>a.jsx(E,{quiet:!0,icon:!0,small:!0,label:i.deleteLabel,isPending:i.pending,isDisabled:i.disabled,onPress:()=>l(i.id),children:a.jsx(ds,{})})}],[e,l]);return a.jsxs(a.Fragment,{children:[s.error&&a.jsx(L,{error:s.error,onRetry:s.retry}),a.jsx(U,{reason:s.flushReason,children:a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(z,{row:!0,items:s.fields}),s.coverage.map(i=>a.jsx(ue,{tone:"warn",children:i.text},i.id)),s.filterText&&a.jsx(E,{small:!0,onPress:t,children:s.filterText}),a.jsx("span",{className:"rp-grow"}),a.jsx(Ge,{label:e("dns.flushAll"),confirmationText:s.confirmationText,isPending:s.flushPending,isDisabled:s.flushPending||s.flushDisabled,onConfirm:s.flush,onAbort:s.abortFlush})]})}),a.jsx(U,{reason:s.deleteReason,above:!0,children:a.jsx(pe,{label:e("ui.cache"),height:442,fit:!0,rows:s.rows,loading:s.loading,empty:s.empty,cols:n})})]})}function ks({enabled:r,initialName:t}){const e=g(),s=Ts(r,t),l=p.useMemo(()=>[{id:"t",label:e("ui.time"),minWidth:140,grow:0,render:n=>a.jsx(B,{at:n.observedAt})},{id:"q",label:e("ui.domain"),minWidth:200,grow:2,isRowHeader:!0,render:n=>a.jsx(D,{children:n.name})},{id:"ty",label:e("ui.type"),minWidth:64,grow:0,drop:3,render:n=>n.type},{id:"s",label:e("ui.device"),minWidth:128,drop:2,render:n=>a.jsx(D,{className:"rp-code",children:n.source})},{id:"r",label:e("dns.result"),minWidth:160,grow:2,render:n=>n.resultError?a.jsx(ae,{small:!0,tone:"err",children:n.result}):a.jsx(D,{className:"rp-code",children:n.result})},{id:"u",label:e("ui.upstream"),minWidth:128,drop:1,render:n=>n.cached?a.jsx(ae,{small:!0,tone:"ok",children:n.upstream}):a.jsx(D,{children:n.upstream})},{id:"e",label:e("ui.elapsed"),minWidth:72,grow:0,align:"end",drop:4,render:n=>n.elapsed}],[e]);return a.jsxs(a.Fragment,{children:[a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(H,{search:!0,label:e("ui.domain"),value:s.name,onChange:s.setName,placeholder:e("dns.logFilterHint"),width:240}),a.jsx(de,{label:e("ui.type"),side:!0,value:s.type,onChange:s.setType,items:s.choices}),a.jsx(H,{search:!0,label:e("ui.device"),value:s.src,onChange:s.setSrc,error:s.srcError,placeholder:"10.0.0.12",width:160}),s.total&&a.jsx(Ie,{help:s.totalHelp,children:a.jsx("span",{className:"rp-label",children:s.total})}),s.loaded&&a.jsx("span",{className:"rp-label",children:s.loaded}),a.jsx("span",{className:"rp-grow"}),a.jsx(Xe,{actions:[{id:"export",label:e("dns.exportLog"),icon:a.jsx(Qe,{}),isDisabled:!s.rows.length,onAction:s.export},{id:"refresh",label:e("refresh"),icon:a.jsx(ze,{className:"rp-spin-on-press"}),isPending:s.refreshing,onAction:s.refresh},...s.hasOlder?[{id:"older",label:e("dns.loadOlder"),isPending:s.loadingOlder,onAction:s.loadOlder}]:[]]})]}),s.error&&a.jsx(L,{error:s.error,onRetry:s.retry}),s.newerWaiting&&a.jsx("p",{className:"rp-note",children:e("dns.newerWaiting")}),a.jsxs("div",{className:"rp-with-panel","data-open":s.detail?"":void 0,children:[a.jsx(pe,{label:e("dns.log"),rowDetail:!0,height:520,rows:s.rows,selected:s.selected,onSelect:s.setSelected,selectOnFocus:s.wide,loading:s.loading,empty:s.empty,cols:l}),a.jsx(Ke,{open:!!s.detail,title:s.detailTitle,onClose:()=>s.setSelected(null),children:s.detail&&a.jsxs(a.Fragment,{children:[a.jsx(z,{inline:!0,items:s.detail.fields}),s.detail.answers.length?a.jsx("div",{className:"rp-list",children:s.detail.answers.map((n,i)=>a.jsx("div",{className:"rp-code",children:n},i))}):a.jsx(C,{children:e("dns.noAnswers")})]})})]})]})}export{Ys as Dns};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Donut-Dusnd_Se.js b/luci-app-honk/root/etc/honk/dashboard/assets/Donut-BhofZH9-.js
similarity index 78%
rename from luci-app-honk/root/etc/honk/dashboard/assets/Donut-Dusnd_Se.js
rename to luci-app-honk/root/etc/honk/dashboard/assets/Donut-BhofZH9-.js
index aaa02b0be..042d33d48 100644
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Donut-Dusnd_Se.js
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Donut-BhofZH9-.js
@@ -1 +1 @@
-import{r as an,j as K}from"./vendor-react-Bf71BWbF.js";import{u as cn,eq as fn}from"./index-zQjLFfuj.js";import{u as gn,i as hn,e as pn,C as yn}from"./layout-B3T-zLsm.js";import{w as dn,c as T,a as mn}from"./array-C0P64tl-.js";const on=Math.abs,w=Math.atan2,N=Math.cos,xn=Math.max,rn=Math.min,b=Math.sin,F=Math.sqrt,S=1e-12,V=Math.PI,X=V/2,W=2*V;function vn(t){return t>1?0:t<-1?V:Math.acos(t)}function ln(t){return t>=1?X:t<=-1?-X:Math.asin(t)}function An(t){return t.innerRadius}function Mn(t){return t.outerRadius}function Rn(t){return t.startAngle}function wn(t){return t.endAngle}function Pn(t){return t&&t.padAngle}function Tn(t,h,v,P,x,A,p,n){var f=v-t,u=P-h,e=p-x,y=n-A,r=y*f-e*u;if(!(r*ri*i+B*B&&(I=L,q=$),{cx:I,cy:q,x01:-e,y01:-y,x11:I*(x/M-1),y11:q*(x/M-1)}}function jn(){var t=An,h=Mn,v=T(0),P=null,x=Rn,A=wn,p=Pn,n=null,f=dn(u);function u(){var e,y,r=+t.apply(this,arguments),a=+h.apply(this,arguments),g=x.apply(this,arguments)-X,d=A.apply(this,arguments)-X,j=on(d-g),c=d>g;if(n||(n=e=f()),aS))n.moveTo(0,0);else if(j>W-S)n.moveTo(a*N(g),a*b(g)),n.arc(0,0,a,g,d,!c),r>S&&(n.moveTo(r*N(d),r*b(d)),n.arc(0,0,r,d,g,c));else{var m=g,o=d,l=g,M=d,R=j,D=j,I=p.apply(this,arguments)/2,q=I>S&&(P?+P.apply(this,arguments):F(r*r+a*a)),L=rn(on(a-r)/2,+v.apply(this,arguments)),$=L,E=L,s,i;if(q>S){var B=ln(q/r*b(I)),O=ln(q/a*b(I));(R-=B*2)>S?(B*=c?1:-1,l+=B,M-=B):(R=0,l=M=(g+d)/2),(D-=O*2)>S?(O*=c?1:-1,m+=O,o-=O):(D=0,m=o=(g+d)/2)}var k=a*N(m),z=a*b(m),G=r*N(M),H=r*b(M);if(L>S){var J=a*N(o),Q=a*b(o),Y=r*N(l),Z=r*b(l),C;if(jS?E>S?(s=U(Y,Z,k,z,a,E,c),i=U(J,Q,G,H,a,E,c),n.moveTo(s.cx+s.x01,s.cy+s.y01),ES)||!(R>S)?n.lineTo(G,H):$>S?(s=U(G,H,J,Q,r,-$,c),i=U(k,z,Y,Z,r,-$,c),n.lineTo(s.cx+s.x01,s.cy+s.y01),$t?1:h>=t?0:NaN}function $n(t){return t}function En(){var t=$n,h=Sn,v=null,P=T(0),x=T(W),A=T(0);function p(n){var f,u=(n=mn(n)).length,e,y,r=0,a=new Array(u),g=new Array(u),d=+P.apply(this,arguments),j=Math.min(W,Math.max(-W,x.apply(this,arguments)-d)),c,m=Math.min(Math.abs(j)/u,A.apply(this,arguments)),o=m*(j<0?-1:1),l;for(f=0;f0&&(r+=l);for(h!=null?a.sort(function(M,R){return h(g[M],g[R])}):v!=null&&a.sort(function(M,R){return v(n[M],n[R])}),f=0,y=r?(j-u*o)/r:0;f0?l*y:0)+o,g[e]={data:n[e],index:f,value:l,startAngle:d,endAngle:c,padAngle:m};return g}return p.value=function(n){return arguments.length?(t=typeof n=="function"?n:T(+n),p):t},p.sortValues=function(n){return arguments.length?(h=n,v=null,p):h},p.sort=function(n){return arguments.length?(v=n,h=null,p):v},p.startAngle=function(n){return arguments.length?(P=typeof n=="function"?n:T(+n),p):P},p.endAngle=function(n){return arguments.length?(x=typeof n=="function"?n:T(+n),p):x},p.padAngle=function(n){return arguments.length?(A=typeof n=="function"?n:T(+n),p):A},p}function In({label:t,rows:h}){const v=cn(),[P,x]=fn(Math.round,120),{tip:A,showAt:p,hide:n}=gn(),[f,u]=an.useState(null),e=h.filter(o=>o.value!==null&&o.value>0),y=x?.width??0,r=x?.height??0,a=hn(e.map(o=>o.value)),g=En().sort(null).value((o,l)=>a[l])(e),d=jn().innerRadius(44).outerRadius(56).digits(3),j=o=>u(o),c=()=>{u(null),n()};an.useLayoutEffect(()=>{const o=f===null?void 0:g[f];if(!o||f===null){n();return}const l=e[f],[M,R]=d.centroid(o);p({x:Math.round((y/2+M)*1e4)/1e4,y:Math.round((r/2+R)*1e4)/1e4,width:y,bounds:{x:0,y:0,width:y,height:r},lines:[`${l.name}${v("ui.labelSeparator")}${v("ui.share",{bytes:l.text,percent:String(l.value)})}`]})});const m=pn(e.length,j,c);return K.jsxs("div",{ref:P,style:{height:"100%",width:"100%",position:"relative"},onPointerLeave:m.onPointerLeave,children:[K.jsx(yn,{tip:A}),x&&K.jsx("svg",{className:"rp-activity-surface",width:y,height:r,viewBox:`0 0 ${y} ${r}`,style:{display:"block"},role:"application","aria-label":t,tabIndex:0,onFocus:m.onFocus,onBlur:m.onBlur,onKeyDown:m.onKeyDown,children:K.jsx("g",{transform:`translate(${y/2},${r/2})`,children:g.map((o,l)=>K.jsx("path",{d:d({...o,endAngle:Math.min(o.endAngle,o.startAngle+359.999*Math.PI/180)})??void 0,fill:e[l].color,stroke:"none",onPointerEnter:()=>j(l),onPointerLeave:m.onPointerLeave},e[l].name))})})]})}export{In as DonutPlot};
+import{r as an,j as K}from"./vendor-react-Bf71BWbF.js";import{u as cn,eH as fn}from"./index-CXHBmSa5.js";import{u as gn,i as hn,e as pn,C as yn}from"./layout-BRLew_nj.js";import{w as dn,c as T,a as mn}from"./array-C0P64tl-.js";const on=Math.abs,w=Math.atan2,k=Math.cos,xn=Math.max,rn=Math.min,b=Math.sin,F=Math.sqrt,S=1e-12,V=Math.PI,X=V/2,W=2*V;function vn(t){return t>1?0:t<-1?V:Math.acos(t)}function ln(t){return t>=1?X:t<=-1?-X:Math.asin(t)}function An(t){return t.innerRadius}function Mn(t){return t.outerRadius}function Rn(t){return t.startAngle}function wn(t){return t.endAngle}function Pn(t){return t&&t.padAngle}function Tn(t,h,v,P,x,A,p,n){var f=v-t,u=P-h,e=p-x,y=n-A,r=y*f-e*u;if(!(r*ri*i+N*N&&(I=L,B=$),{cx:I,cy:B,x01:-e,y01:-y,x11:I*(x/M-1),y11:B*(x/M-1)}}function jn(){var t=An,h=Mn,v=T(0),P=null,x=Rn,A=wn,p=Pn,n=null,f=dn(u);function u(){var e,y,r=+t.apply(this,arguments),a=+h.apply(this,arguments),g=x.apply(this,arguments)-X,d=A.apply(this,arguments)-X,j=on(d-g),c=d>g;if(n||(n=e=f()),aS))n.moveTo(0,0);else if(j>W-S)n.moveTo(a*k(g),a*b(g)),n.arc(0,0,a,g,d,!c),r>S&&(n.moveTo(r*k(d),r*b(d)),n.arc(0,0,r,d,g,c));else{var m=g,o=d,l=g,M=d,R=j,D=j,I=p.apply(this,arguments)/2,B=I>S&&(P?+P.apply(this,arguments):F(r*r+a*a)),L=rn(on(a-r)/2,+v.apply(this,arguments)),$=L,E=L,s,i;if(B>S){var N=ln(B/r*b(I)),H=ln(B/a*b(I));(R-=N*2)>S?(N*=c?1:-1,l+=N,M-=N):(R=0,l=M=(g+d)/2),(D-=H*2)>S?(H*=c?1:-1,m+=H,o-=H):(D=0,m=o=(g+d)/2)}var q=a*k(m),z=a*b(m),O=r*k(M),G=r*b(M);if(L>S){var J=a*k(o),Q=a*b(o),Y=r*k(l),Z=r*b(l),C;if(jS?E>S?(s=U(Y,Z,q,z,a,E,c),i=U(J,Q,O,G,a,E,c),n.moveTo(s.cx+s.x01,s.cy+s.y01),ES)||!(R>S)?n.lineTo(O,G):$>S?(s=U(O,G,J,Q,r,-$,c),i=U(q,z,Y,Z,r,-$,c),n.lineTo(s.cx+s.x01,s.cy+s.y01),$t?1:h>=t?0:NaN}function $n(t){return t}function En(){var t=$n,h=Sn,v=null,P=T(0),x=T(W),A=T(0);function p(n){var f,u=(n=mn(n)).length,e,y,r=0,a=new Array(u),g=new Array(u),d=+P.apply(this,arguments),j=Math.min(W,Math.max(-W,x.apply(this,arguments)-d)),c,m=Math.min(Math.abs(j)/u,A.apply(this,arguments)),o=m*(j<0?-1:1),l;for(f=0;f0&&(r+=l);for(h!=null?a.sort(function(M,R){return h(g[M],g[R])}):v!=null&&a.sort(function(M,R){return v(n[M],n[R])}),f=0,y=r?(j-u*o)/r:0;f0?l*y:0)+o,g[e]={data:n[e],index:f,value:l,startAngle:d,endAngle:c,padAngle:m};return g}return p.value=function(n){return arguments.length?(t=typeof n=="function"?n:T(+n),p):t},p.sortValues=function(n){return arguments.length?(h=n,v=null,p):h},p.sort=function(n){return arguments.length?(v=n,h=null,p):v},p.startAngle=function(n){return arguments.length?(P=typeof n=="function"?n:T(+n),p):P},p.endAngle=function(n){return arguments.length?(x=typeof n=="function"?n:T(+n),p):x},p.padAngle=function(n){return arguments.length?(A=typeof n=="function"?n:T(+n),p):A},p}function In({label:t,rows:h}){const v=cn(),[P,x]=fn(Math.round,120),{tip:A,showAt:p,hide:n}=gn(),[f,u]=an.useState(null),e=h.filter(o=>o.value!==null&&o.value>0),y=x?.width??0,r=x?.height??0,a=hn(e.map(o=>o.value)),g=En().sort(null).value((o,l)=>a[l])(e),d=jn().innerRadius(44).outerRadius(56).digits(3),j=o=>u(o),c=()=>{u(null),n()};an.useLayoutEffect(()=>{const o=f===null?void 0:g[f];if(!o||f===null){n();return}const l=e[f],[M,R]=d.centroid(o);p({x:Math.round((y/2+M)*1e4)/1e4,y:Math.round((r/2+R)*1e4)/1e4,width:y,bounds:{x:0,y:0,width:y,height:r},lines:[`${l.name}${v("ui.labelSeparator")}${v("ui.share",{bytes:l.text,percent:String(l.value)})}`]})});const m=pn(e.length,j,c);return K.jsxs("div",{ref:P,style:{height:"100%",width:"100%",position:"relative"},onPointerLeave:m.onPointerLeave,children:[K.jsx(yn,{tip:A}),x&&K.jsx("svg",{className:"rp-activity-surface",width:y,height:r,viewBox:`0 0 ${y} ${r}`,style:{display:"block"},role:"application","aria-label":t,tabIndex:0,onFocus:m.onFocus,onBlur:m.onBlur,onKeyDown:m.onKeyDown,children:K.jsx("g",{transform:`translate(${y/2},${r/2})`,children:g.map((o,l)=>K.jsx("path",{d:d({...o,endAngle:Math.min(o.endAngle,o.startAngle+359.999*Math.PI/180)})??void 0,fill:e[l].color,stroke:"none",onPointerEnter:()=>j(l),onPointerLeave:m.onPointerLeave},e[l].name))})})]})}export{In as DonutPlot};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Events-B-WlUhq0.js b/luci-app-honk/root/etc/honk/dashboard/assets/Events-B-WlUhq0.js
new file mode 100644
index 000000000..87416e68b
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Events-B-WlUhq0.js
@@ -0,0 +1,2 @@
+import{r as v,j as n}from"./vendor-react-Bf71BWbF.js";import{a0 as b,dy as k,dz as f,aq as j,bo as y,u as g,a2 as E,a as T,a5 as L,dA as N,bc as D,dB as H,dC as C,dD as R,dE as K,aE as p,bm as M,aD as _,b2 as A,aC as F,B as O,aF as S,E as W}from"./index-CXHBmSa5.js";import{D as B}from"./Table-D0NFHHNQ.js";import{d as I,e as P}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";const h={buffer_overflow:["event.gap.overflow","event.gapHelp.overflow"],evicted:["event.gap.evicted","event.gapHelp.evicted"]};function V(e,t){const a=e.event==="flow.gap"&&Object.hasOwn(h,e.data.reason)?h[e.data.reason]:void 0;return a&&{title:t(a[0]),text:t(a[1])}}const w=new WeakMap;function q(e,t,a,l){const s=w.get(e);if(s&&s.locale===t)return s.row;const o=l?{key:"event.lostHistory"}:k(e,a),i={id:e.id,timestamp:j(e.data.observed_at,t),iso:e.data.observed_at,kind:e.event,kindText:b(f,e.event,a),summary:a(o.key,o.params),help:V(e,a)};return w.set(e,{locale:t,row:i}),i}function z(e,t,a,l,s,o,i,c,r=!1,u=()=>!1){const m=t==="without-runtime"||c.includes(t)?t:"all",x=e.filter(d=>m==="all"||(m==="without-runtime"?d.event!=="runtime.updated":d.event===m)).slice(0,s);return{kind:m,rows:x.map(d=>q(d,o,i,u(d))),kinds:[{id:"without-runtime",label:i("event.withoutRuntime")},{id:"all",label:i("event.allKinds")},...c.map(d=>({id:d,label:b(f,d,i)}))],status:r&&l!==!1?{tone:"err",text:i("event.disconnected")}:{tone:a?"ok":l===null?"muted":"warn",text:i(l===!1?"event.unavailable":a?"event.connected":l===null?"ui.loading":"event.reconnecting")},limitText:i("event.limit",{n:s}),shown:x}}function J(e){return JSON.stringify(e,null,2)+`
+`}function G(){const e=y(),t=g(),a=E[T()],s=L().data?.resources.events.kinds,[o,i]=v.useState("without-runtime"),c=o!=="all"&&o!=="runtime.updated"&&s?.includes(o),r=N(o!=="without-runtime"&&!c),u=v.useMemo(()=>z(r.events,o,r.connected,r.available,K,a,t,s??[],!!r.error,R),[r.events,o,r.connected,r.available,r.error,a,t,s]);return D(u.kind,i),{...u,setKind:i,cursor:r.cursor,error:r.error,retry:()=>void H().then(()=>C(e)),loading:!r.error&&!r.connected&&r.available!==!1&&!r.events.length,export:()=>I(P("doona-events","json"),J(u.shown),"application/json")}}function te(){const e=g(),t=G(),a=v.useMemo(()=>[{id:"t",label:e("ui.time"),minWidth:200,grow:0,drop:1,render:s=>n.jsx(p,{className:"rp-code",text:s.iso,children:s.timestamp})},{id:"k",label:e("event.kind"),minWidth:168,drop:2,render:s=>n.jsx(p,{text:s.kind,children:s.kindText})},{id:"m",label:e("event.summary"),minWidth:240,isRowHeader:!0,render:s=>n.jsx(M,{fill:!0,help:s.help,children:n.jsx(p,{children:s.summary})})}],[e]),l=v.useCallback(s=>n.jsx(_,{inline:!0,items:[[e("ui.time"),s.timestamp],[e("event.kind"),s.kindText],[e("event.summary"),s.summary]]}),[e]);return n.jsxs("div",{className:"rp-page",children:[n.jsxs("div",{className:"rp-toolbar",children:[n.jsx(A,{label:e("event.kind"),side:!0,value:t.kind,onChange:t.setKind,items:t.kinds}),n.jsx(F,{small:!0,tone:t.status.tone,children:t.status.text}),t.cursor&&n.jsx(p,{text:t.cursor,children:n.jsx("span",{className:"rp-label",children:e("event.cursor")})}),n.jsx("span",{className:"rp-label",children:t.limitText}),n.jsx("span",{className:"rp-grow"}),n.jsxs(O,{isDisabled:!t.rows.length,onPress:t.export,children:[n.jsx(S,{}),e("event.export")]})]}),t.error&&n.jsx(W,{error:t.error,onRetry:t.retry}),n.jsx(B,{label:e("nav.events"),stream:!0,fit:!0,height:442,loading:t.loading,rows:t.rows,empty:e("event.empty"),cols:a,detail:l})]})}export{te as Events};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Events-BUl_BoAv.js b/luci-app-honk/root/etc/honk/dashboard/assets/Events-BUl_BoAv.js
deleted file mode 100644
index bf4840d21..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Events-BUl_BoAv.js
+++ /dev/null
@@ -1,2 +0,0 @@
-import{r as x,j as r}from"./vendor-react-Bf71BWbF.js";import{V as w,dh as k,di as b,ah as g,be as j,u as f,X as y,_ as E,$ as T,b2 as L,dj as N,dk as D,dl as M,dm as R,av as p,aT as _,at as K,B as S,aw as W,E as A}from"./index-zQjLFfuj.js";import{D as C}from"./Table-DLlwyNFJ.js";import{u as F}from"./logs-KkruktUh.js";import{d as V,e as B}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";const v=new WeakMap;function H(t,e,o,n){const l=v.get(t);if(l&&l.locale===e)return l.row;const i=n?{key:"event.lostHistory"}:k(t,o),a={id:t.id,timestamp:g(t.data.observed_at,e),iso:t.data.observed_at,kind:t.event,kindText:w(b,t.event,o),summary:o(i.key,i.params)};return v.set(t,{locale:e,row:a}),a}function I(t,e,o,n,l,i,a,m,s=!1,u=()=>!1){const c=e==="without-runtime"||m.includes(e)?e:"all",h=t.filter(d=>c==="all"||(c==="without-runtime"?d.event!=="runtime.updated":d.event===c)).slice(0,l);return{kind:c,rows:h.map(d=>H(d,i,a,u(d))),kinds:[{id:"without-runtime",label:a("event.withoutRuntime")},{id:"all",label:a("event.allKinds")},...m.map(d=>({id:d,label:w(b,d,a)}))],status:s&&n!==!1?{tone:"err",text:a("event.disconnected")}:{tone:o?"ok":n===null?"muted":"warn",text:a(n===!1?"event.unavailable":o?"event.connected":n===null?"ui.loading":"event.reconnecting")},limitText:a("event.limit",{n:l}),shown:h}}function O(t){return JSON.stringify(t,null,2)+`
-`}function P(){const t=j(),e=f(),o=y[E()],l=T().data?.resources.events.kinds,[i,a]=x.useState("without-runtime"),m=i!=="all"&&i!=="runtime.updated"&&l?.includes(i),s=F(i!=="without-runtime"&&!m),u=x.useMemo(()=>I(s.events,i,s.connected,s.available,R,o,e,l??[],!!s.error,M),[s.events,i,s.connected,s.available,s.error,o,e,l]);return L(u.kind,a),{...u,setKind:a,cursor:s.cursor,error:s.error,retry:()=>void N().then(()=>D(t)),loading:!s.error&&!s.connected&&s.available!==!1&&!s.events.length,export:()=>V(B("doona-events","json"),O(u.shown),"application/json")}}function Y(){const t=f(),e=P(),o=x.useMemo(()=>[{id:"t",label:t("ui.time"),minWidth:200,grow:0,drop:1,render:n=>r.jsx(p,{className:"rp-code",text:n.iso,children:n.timestamp})},{id:"k",label:t("event.kind"),minWidth:168,drop:2,render:n=>r.jsx(p,{text:n.kind,children:n.kindText})},{id:"m",label:t("event.summary"),minWidth:240,isRowHeader:!0,render:n=>n.summary}],[t]);return r.jsxs("div",{className:"rp-page",children:[r.jsxs("div",{className:"rp-toolbar",children:[r.jsx(_,{label:t("event.kind"),side:!0,value:e.kind,onChange:e.setKind,items:e.kinds}),r.jsx(K,{small:!0,tone:e.status.tone,children:e.status.text}),e.cursor&&r.jsx(p,{text:e.cursor,children:r.jsx("span",{className:"rp-label",children:t("event.cursor")})}),r.jsx("span",{className:"rp-label",children:e.limitText}),r.jsx("span",{className:"rp-grow"}),r.jsxs(S,{isDisabled:!e.rows.length,onPress:e.export,children:[r.jsx(W,{}),t("event.export")]})]}),e.error&&r.jsx(A,{error:e.error,onRetry:e.retry}),r.jsx(C,{label:t("nav.events"),stream:!0,fit:!0,height:442,loading:e.loading,rows:e.rows,empty:t("event.empty"),cols:o})]})}export{Y as Events};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-BgQ_tYB6.js b/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-BgQ_tYB6.js
new file mode 100644
index 000000000..ca77d8bf0
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-BgQ_tYB6.js
@@ -0,0 +1 @@
+import{j as s}from"./vendor-react-Bf71BWbF.js";import{aE as t}from"./index-CXHBmSa5.js";function p({facts:l,lead:r}){return l.length?s.jsx("dl",{className:"rp-strip rp-facts"+(r?" rp-facts-lead":""),style:{"--facts":l.length,"--facts-rest":l.length-1},children:l.map((e,i)=>s.jsxs("div",{className:"rp-card"+(e.tone?" "+e.tone:""),children:[s.jsxs("dt",{className:"rp-tile-head"+(e.tint?" rp-tint-"+e.tint:""),children:[e.icon,e.label]}),s.jsxs("dd",{className:"rp-tile-body",children:[r&&i===0?s.jsx(t,{className:"rp-big",cut:"start",children:e.value}):s.jsx("span",{className:"rp-big",title:e.value,children:e.value}),e.caption&&s.jsx("span",{className:"rp-fact-caption",title:e.caption,children:e.caption})]})]},e.label))}):null}export{p as F};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-vcLr7nBw.js b/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-vcLr7nBw.js
deleted file mode 100644
index 3f837830a..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/FactStrip-vcLr7nBw.js
+++ /dev/null
@@ -1 +0,0 @@
-import{j as s}from"./vendor-react-Bf71BWbF.js";import{b1 as t,av as a,b7 as p}from"./index-zQjLFfuj.js";function c({facts:r,lead:l}){const i=t(p);return r.length?s.jsx("dl",{className:"rp-strip rp-facts"+(l?" rp-facts-lead":""),style:{"--facts":r.length},children:r.map((e,n)=>s.jsxs("div",{className:"rp-card"+(e.tone?" "+e.tone:""),children:[s.jsxs("dt",{className:"rp-tile-head"+(e.tint?" rp-tint-"+e.tint:""),children:[e.icon,e.label]}),s.jsxs("dd",{className:"rp-tile-body",children:[l&&i&&n===0?s.jsx(a,{className:"rp-big",cut:"start",children:e.value}):s.jsx("span",{className:"rp-big",title:e.value,children:e.value}),e.caption&&s.jsx("span",{className:"rp-fact-caption",title:e.caption,children:e.caption})]})]},e.label))}):null}export{c as F};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-DU_9AgrU.js b/luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-CPapuywx.js
similarity index 98%
rename from luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-DU_9AgrU.js
rename to luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-CPapuywx.js
index 6ac9aa8ee..0152d9347 100644
--- a/luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-DU_9AgrU.js
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/ListLayout-CPapuywx.js
@@ -1 +1 @@
-import{d$ as v}from"./index-zQjLFfuj.js";import{$ as R,c,a as S,b as p}from"./Virtualizer-CTh266-x.js";const f=48;class N extends R{constructor(t={}){super(),this.rowSize=t?.rowSize??t?.rowHeight??null,this.orientation=t.orientation??"vertical",this.estimatedRowSize=t?.estimatedRowSize??t?.estimatedRowHeight??null,this.headingSize=t?.headingSize??t?.headingHeight??null,this.estimatedHeadingSize=t?.estimatedHeadingSize??t?.estimatedHeadingHeight??null,this.loaderSize=t?.loaderSize??t?.loaderHeight??null,this.dropIndicatorThickness=t.dropIndicatorThickness||2,this.gap=t.gap||0,this.padding=t.padding||0,this.layoutNodes=new Map,this.rootNodes=[],this.lastCollection=null,this.invalidateEverything=!1,this.validRect=new c,this.requestedRect=new c,this.contentSize=new S}get collection(){return this.virtualizer.collection}get rowHeight(){return this.rowSize}get estimatedRowHeight(){return this.estimatedRowSize}get headingHeight(){return this.headingSize}get estimatedHeadingHeight(){return this.estimatedHeadingSize}get loaderHeight(){return this.loaderSize}getLayoutInfo(t){return this.ensureLayoutInfo(t),this.layoutNodes.get(t)?.layoutInfo||null}getVisibleLayoutInfos(t){let e=this.orientation==="horizontal"?"x":"y",i=this.orientation==="horizontal"?"width":"height";if(t[i]>1){let s=(this.rowSize??this.estimatedRowSize??f)+this.gap;t=t.copy();let o=Math.floor(t[e]/s)*s,l=t[i]+t[e]-o;t[e]=o,t[i]=Math.ceil(l/s)*s}this.layoutIfNeeded(t);let r=[],h=s=>{for(let o of s)this.isVisible(o,t)&&(r.push(o.layoutInfo),o.children&&h(o.children))};return h(this.rootNodes),r}layoutIfNeeded(t){if(this.lastCollection){this.requestedRect.containsRect(t)||(this.requestedRect=this.requestedRect.union(t),this.rootNodes=this.buildCollection());for(let e of this.virtualizer.persistedKeys)if(this.ensureLayoutInfo(e))return}}ensureLayoutInfo(t){return!this.layoutNodes.has(t)&&this.requestedRect.areaa.type!=="content"),s=h.filter(a=>a.type==="loader"),o=[],l=e?.size===0;l&&(t=0);for(let a of h){let n=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a.type==="item"&&t+nthis.requestedRect[r]){let u=h.indexOf(a);for(let y of s){let g=h.indexOf(y);t+=(g-u-1)*n;let z=this.orientation==="horizontal"?this.buildChild(y,t,this.padding,null):this.buildChild(y,this.padding,t,null);o.push(z),t=z.layoutInfo.rect[r],u=g}t+=(h.length-u-1)*n;break}}return t=Math.max(t-this.gap,0),t+=l?0:this.padding,this.contentSize=this.orientation==="horizontal"?new S(t,this.virtualizer.size.height):new S(this.virtualizer.size.width,t),o}isValid(t,e){let i=this.layoutNodes.get(t.key),r=this.orientation==="horizontal"?"x":"y";return!this.invalidateEverything&&!!i&&i.node===t&&e===i.layoutInfo.rect[r]&&i.layoutInfo.rect.intersects(this.validRect)&&i.validRect.containsRect(i.layoutInfo.rect.intersection(this.requestedRect))}buildChild(t,e,i,r){if(this.isValid(t,this.orientation==="horizontal"?e:i))return this.layoutNodes.get(t.key);let h=this.buildNode(t,e,i);return h.layoutInfo.parentKey=r??null,h.layoutInfo.allowOverflow=!0,this.layoutNodes.set(t.key,h),h}buildNode(t,e,i){switch(t.type){case"section":return this.buildSection(t,e,i);case"item":return this.buildItem(t,e,i);case"header":return this.buildSectionHeader(t,e,i);case"loader":return this.buildLoader(t,e,i);case"separator":return this.buildItem(t,e,i);default:throw new Error("Unsupported node type: "+t.type)}}buildLoader(t,e,i){let r=new c(e,i,this.padding,0),h=new p(t.type,t.key,r);return this.orientation==="horizontal"?(r.height=this.virtualizer.contentSize.height-this.padding-i,r.width=t.props.isLoading?this.loaderSize??this.rowSize??this.estimatedRowSize??f:0):(r.width=this.virtualizer.contentSize.width-this.padding-e,r.height=t.props.isLoading?this.loaderSize??this.rowSize??this.estimatedRowSize??f:0),{layoutInfo:h,validRect:r.intersection(this.requestedRect)}}buildSection(t,e,i){let r=this.virtualizer.collection,h=this.virtualizer.size.width-this.padding-e,s=this.virtualizer.size.height-this.padding-i,o=this.orientation==="horizontal"?new c(e,i,0,s):new c(e,i,h,0),l=new p(t.type,t.key,o),a=this.orientation==="horizontal"?e:i,n=this.orientation==="horizontal"?"x":"y",d=this.orientation==="horizontal"?"maxX":"maxY",u=this.orientation==="horizontal"?"width":"height",y=0,g=[];for(let z of v(t,r)){if(z.type==="content")continue;let w=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a+wthis.requestedRect[d]){a+=([...v(t,r)].length-(g.length+y))*w;break}}return a-=this.gap,o[u]=a-(this.orientation==="horizontal"?e:i),{layoutInfo:l,children:g,validRect:l.rect.intersection(this.requestedRect),node:t}}buildSectionHeader(t,e,i){let r=this.orientation==="horizontal"?"height":"width",h=this.orientation==="horizontal"?"width":"height",s=this.virtualizer.size[r]-this.padding-(this.orientation==="horizontal"?i:e),o=this.headingSize,l=!1;if(o==null){let d=this.layoutNodes.get(t.key),u=d?.layoutInfo;if(u){let y=this.virtualizer.collection.getItem(t.key),g=this.lastCollection?this.lastCollection.getItem(t.key):null;o=d.layoutInfo.rect[h],l=s!==u.rect[r]||y!==g||u.estimatedSize}else o=t.rendered?this.estimatedHeadingSize:0,l=!0}o==null&&(o=f);let a=this.orientation==="horizontal"?new c(e,i,o,s-i):new c(e,i,s-e,o),n=new p("header",t.key,a);return n.estimatedSize=l,{layoutInfo:n,children:[],validRect:n.rect.intersection(this.requestedRect),node:t}}buildItem(t,e,i){let r=this.orientation==="horizontal"?"height":"width",h=this.orientation==="horizontal"?"width":"height",s=this.virtualizer.size[r]-this.padding-(this.orientation==="horizontal"?i:e),o=this.rowSize,l=!1;if(o==null){let d=this.layoutNodes.get(t.key);d?(o=d.layoutInfo.rect[h],l=s!==d.layoutInfo.rect[r]||t!==d.node||d.layoutInfo.estimatedSize):(o=this.estimatedRowSize,l=!0)}o==null&&(o=f);let a=this.orientation==="horizontal"?new c(e,i,o,s):new c(e,i,s,o),n=new p(t.type,t.key,a);return n.estimatedSize=l,{layoutInfo:n,children:[],validRect:n.rect.intersection(this.requestedRect),node:t}}updateItemSize(t,e){let i=this.layoutNodes.get(t);if(!i)return!1;let r=this.virtualizer.collection,h=i.layoutInfo,s=this.orientation==="horizontal"?"x":"y",o=this.orientation==="horizontal"?"width":"height";if(h.estimatedSize=!1,h.rect[o]!==e[o]){let l=h.copy();l.rect[o]=e[o],i.layoutInfo=l,this.validRect[o]=Math.min(this.validRect[o],h.rect[s]-this.validRect[s]),i.node?.type==="item"&&(this.requestedRect[o]+=l.rect[o]-h.rect[o]),this.updateLayoutNode(t,h,l);let a=h.parentKey!=null?r.getItem(h.parentKey):null;for(;a;)this.updateLayoutNode(a.key,h,l),a=a.parentKey!=null?r.getItem(a.parentKey):null;return!0}return!1}updateLayoutNode(t,e,i){let r=this.layoutNodes.get(t);r&&(r.validRect=r.validRect.intersection(this.validRect),r.layoutInfo===e&&(r.layoutInfo=i))}getContentSize(){return this.contentSize}getDropTargetFromPoint(t,e,i){t+=this.virtualizer.visibleRect.x,e+=this.virtualizer.visibleRect.y;let r=new c(t,Math.max(0,e-this.gap),1,Math.max(1,this.gap*2)),h=this.getVisibleLayoutInfos(r),s=null,o=1/0;for(let d of h){if(!d.rect.intersects(r))continue;let u=Math.abs(d.rect.y-e),y=Math.abs(d.rect.maxY-e),g=Math.min(u,y);g=a.maxY-10&&i({...n,dropPosition:"after"})&&(n.dropPosition="after"):e<=a.y+a.height/2&&i({...n,dropPosition:"before"})?n.dropPosition="before":i({...n,dropPosition:"after"})&&(n.dropPosition="after"),n}getDropTargetLayoutInfo(t){let e=this.getLayoutInfo(t.key),i;if(t.dropPosition==="before")i=this.orientation==="horizontal"?new c(Math.max(0,e.rect.x-this.dropIndicatorThickness/2),e.rect.y,this.dropIndicatorThickness,e.rect.height):new c(e.rect.x,Math.max(0,e.rect.y-this.dropIndicatorThickness/2),e.rect.width,this.dropIndicatorThickness);else if(t.dropPosition==="after"){let r=this.collection.getItem(t.key);if(r){let h=r.level??0,s=this.collection.getKeyAfter(t.key);for(;s!=null;){let o=this.collection.getItem(s);if(!o||o.level<=h)break;e=this.getLayoutInfo(s)||e,s=this.collection.getKeyAfter(s)}}i=this.orientation==="horizontal"?new c(e.rect.maxX-this.dropIndicatorThickness/2,e.rect.y,this.dropIndicatorThickness,e.rect.height):new c(e.rect.x,e.rect.maxY-this.dropIndicatorThickness/2,e.rect.width,this.dropIndicatorThickness)}else i=e.rect;return new p("dropIndicator",t.key+":"+t.dropPosition,i)}}function H(I,t){const e=[];for(const i of I)t(i)&&e.push(i);return e}export{N as $};
+import{ee as v}from"./index-CXHBmSa5.js";import{$ as R,c,a as S,b as p}from"./Virtualizer--Vfl8O3n.js";const f=48;class N extends R{constructor(t={}){super(),this.rowSize=t?.rowSize??t?.rowHeight??null,this.orientation=t.orientation??"vertical",this.estimatedRowSize=t?.estimatedRowSize??t?.estimatedRowHeight??null,this.headingSize=t?.headingSize??t?.headingHeight??null,this.estimatedHeadingSize=t?.estimatedHeadingSize??t?.estimatedHeadingHeight??null,this.loaderSize=t?.loaderSize??t?.loaderHeight??null,this.dropIndicatorThickness=t.dropIndicatorThickness||2,this.gap=t.gap||0,this.padding=t.padding||0,this.layoutNodes=new Map,this.rootNodes=[],this.lastCollection=null,this.invalidateEverything=!1,this.validRect=new c,this.requestedRect=new c,this.contentSize=new S}get collection(){return this.virtualizer.collection}get rowHeight(){return this.rowSize}get estimatedRowHeight(){return this.estimatedRowSize}get headingHeight(){return this.headingSize}get estimatedHeadingHeight(){return this.estimatedHeadingSize}get loaderHeight(){return this.loaderSize}getLayoutInfo(t){return this.ensureLayoutInfo(t),this.layoutNodes.get(t)?.layoutInfo||null}getVisibleLayoutInfos(t){let e=this.orientation==="horizontal"?"x":"y",i=this.orientation==="horizontal"?"width":"height";if(t[i]>1){let s=(this.rowSize??this.estimatedRowSize??f)+this.gap;t=t.copy();let o=Math.floor(t[e]/s)*s,l=t[i]+t[e]-o;t[e]=o,t[i]=Math.ceil(l/s)*s}this.layoutIfNeeded(t);let r=[],h=s=>{for(let o of s)this.isVisible(o,t)&&(r.push(o.layoutInfo),o.children&&h(o.children))};return h(this.rootNodes),r}layoutIfNeeded(t){if(this.lastCollection){this.requestedRect.containsRect(t)||(this.requestedRect=this.requestedRect.union(t),this.rootNodes=this.buildCollection());for(let e of this.virtualizer.persistedKeys)if(this.ensureLayoutInfo(e))return}}ensureLayoutInfo(t){return!this.layoutNodes.has(t)&&this.requestedRect.areaa.type!=="content"),s=h.filter(a=>a.type==="loader"),o=[],l=e?.size===0;l&&(t=0);for(let a of h){let n=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a.type==="item"&&t+nthis.requestedRect[r]){let u=h.indexOf(a);for(let y of s){let g=h.indexOf(y);t+=(g-u-1)*n;let z=this.orientation==="horizontal"?this.buildChild(y,t,this.padding,null):this.buildChild(y,this.padding,t,null);o.push(z),t=z.layoutInfo.rect[r],u=g}t+=(h.length-u-1)*n;break}}return t=Math.max(t-this.gap,0),t+=l?0:this.padding,this.contentSize=this.orientation==="horizontal"?new S(t,this.virtualizer.size.height):new S(this.virtualizer.size.width,t),o}isValid(t,e){let i=this.layoutNodes.get(t.key),r=this.orientation==="horizontal"?"x":"y";return!this.invalidateEverything&&!!i&&i.node===t&&e===i.layoutInfo.rect[r]&&i.layoutInfo.rect.intersects(this.validRect)&&i.validRect.containsRect(i.layoutInfo.rect.intersection(this.requestedRect))}buildChild(t,e,i,r){if(this.isValid(t,this.orientation==="horizontal"?e:i))return this.layoutNodes.get(t.key);let h=this.buildNode(t,e,i);return h.layoutInfo.parentKey=r??null,h.layoutInfo.allowOverflow=!0,this.layoutNodes.set(t.key,h),h}buildNode(t,e,i){switch(t.type){case"section":return this.buildSection(t,e,i);case"item":return this.buildItem(t,e,i);case"header":return this.buildSectionHeader(t,e,i);case"loader":return this.buildLoader(t,e,i);case"separator":return this.buildItem(t,e,i);default:throw new Error("Unsupported node type: "+t.type)}}buildLoader(t,e,i){let r=new c(e,i,this.padding,0),h=new p(t.type,t.key,r);return this.orientation==="horizontal"?(r.height=this.virtualizer.contentSize.height-this.padding-i,r.width=t.props.isLoading?this.loaderSize??this.rowSize??this.estimatedRowSize??f:0):(r.width=this.virtualizer.contentSize.width-this.padding-e,r.height=t.props.isLoading?this.loaderSize??this.rowSize??this.estimatedRowSize??f:0),{layoutInfo:h,validRect:r.intersection(this.requestedRect)}}buildSection(t,e,i){let r=this.virtualizer.collection,h=this.virtualizer.size.width-this.padding-e,s=this.virtualizer.size.height-this.padding-i,o=this.orientation==="horizontal"?new c(e,i,0,s):new c(e,i,h,0),l=new p(t.type,t.key,o),a=this.orientation==="horizontal"?e:i,n=this.orientation==="horizontal"?"x":"y",d=this.orientation==="horizontal"?"maxX":"maxY",u=this.orientation==="horizontal"?"width":"height",y=0,g=[];for(let z of v(t,r)){if(z.type==="content")continue;let w=(this.rowSize??this.estimatedRowSize??f)+this.gap;if(a+wthis.requestedRect[d]){a+=([...v(t,r)].length-(g.length+y))*w;break}}return a-=this.gap,o[u]=a-(this.orientation==="horizontal"?e:i),{layoutInfo:l,children:g,validRect:l.rect.intersection(this.requestedRect),node:t}}buildSectionHeader(t,e,i){let r=this.orientation==="horizontal"?"height":"width",h=this.orientation==="horizontal"?"width":"height",s=this.virtualizer.size[r]-this.padding-(this.orientation==="horizontal"?i:e),o=this.headingSize,l=!1;if(o==null){let d=this.layoutNodes.get(t.key),u=d?.layoutInfo;if(u){let y=this.virtualizer.collection.getItem(t.key),g=this.lastCollection?this.lastCollection.getItem(t.key):null;o=d.layoutInfo.rect[h],l=s!==u.rect[r]||y!==g||u.estimatedSize}else o=t.rendered?this.estimatedHeadingSize:0,l=!0}o==null&&(o=f);let a=this.orientation==="horizontal"?new c(e,i,o,s-i):new c(e,i,s-e,o),n=new p("header",t.key,a);return n.estimatedSize=l,{layoutInfo:n,children:[],validRect:n.rect.intersection(this.requestedRect),node:t}}buildItem(t,e,i){let r=this.orientation==="horizontal"?"height":"width",h=this.orientation==="horizontal"?"width":"height",s=this.virtualizer.size[r]-this.padding-(this.orientation==="horizontal"?i:e),o=this.rowSize,l=!1;if(o==null){let d=this.layoutNodes.get(t.key);d?(o=d.layoutInfo.rect[h],l=s!==d.layoutInfo.rect[r]||t!==d.node||d.layoutInfo.estimatedSize):(o=this.estimatedRowSize,l=!0)}o==null&&(o=f);let a=this.orientation==="horizontal"?new c(e,i,o,s):new c(e,i,s,o),n=new p(t.type,t.key,a);return n.estimatedSize=l,{layoutInfo:n,children:[],validRect:n.rect.intersection(this.requestedRect),node:t}}updateItemSize(t,e){let i=this.layoutNodes.get(t);if(!i)return!1;let r=this.virtualizer.collection,h=i.layoutInfo,s=this.orientation==="horizontal"?"x":"y",o=this.orientation==="horizontal"?"width":"height";if(h.estimatedSize=!1,h.rect[o]!==e[o]){let l=h.copy();l.rect[o]=e[o],i.layoutInfo=l,this.validRect[o]=Math.min(this.validRect[o],h.rect[s]-this.validRect[s]),i.node?.type==="item"&&(this.requestedRect[o]+=l.rect[o]-h.rect[o]),this.updateLayoutNode(t,h,l);let a=h.parentKey!=null?r.getItem(h.parentKey):null;for(;a;)this.updateLayoutNode(a.key,h,l),a=a.parentKey!=null?r.getItem(a.parentKey):null;return!0}return!1}updateLayoutNode(t,e,i){let r=this.layoutNodes.get(t);r&&(r.validRect=r.validRect.intersection(this.validRect),r.layoutInfo===e&&(r.layoutInfo=i))}getContentSize(){return this.contentSize}getDropTargetFromPoint(t,e,i){t+=this.virtualizer.visibleRect.x,e+=this.virtualizer.visibleRect.y;let r=new c(t,Math.max(0,e-this.gap),1,Math.max(1,this.gap*2)),h=this.getVisibleLayoutInfos(r),s=null,o=1/0;for(let d of h){if(!d.rect.intersects(r))continue;let u=Math.abs(d.rect.y-e),y=Math.abs(d.rect.maxY-e),g=Math.min(u,y);g=a.maxY-10&&i({...n,dropPosition:"after"})&&(n.dropPosition="after"):e<=a.y+a.height/2&&i({...n,dropPosition:"before"})?n.dropPosition="before":i({...n,dropPosition:"after"})&&(n.dropPosition="after"),n}getDropTargetLayoutInfo(t){let e=this.getLayoutInfo(t.key),i;if(t.dropPosition==="before")i=this.orientation==="horizontal"?new c(Math.max(0,e.rect.x-this.dropIndicatorThickness/2),e.rect.y,this.dropIndicatorThickness,e.rect.height):new c(e.rect.x,Math.max(0,e.rect.y-this.dropIndicatorThickness/2),e.rect.width,this.dropIndicatorThickness);else if(t.dropPosition==="after"){let r=this.collection.getItem(t.key);if(r){let h=r.level??0,s=this.collection.getKeyAfter(t.key);for(;s!=null;){let o=this.collection.getItem(s);if(!o||o.level<=h)break;e=this.getLayoutInfo(s)||e,s=this.collection.getKeyAfter(s)}}i=this.orientation==="horizontal"?new c(e.rect.maxX-this.dropIndicatorThickness/2,e.rect.y,this.dropIndicatorThickness,e.rect.height):new c(e.rect.x,e.rect.maxY-this.dropIndicatorThickness/2,e.rect.width,this.dropIndicatorThickness)}else i=e.rect;return new p("dropIndicator",t.key+":"+t.dropPosition,i)}}function H(I,t){const e=[];for(const i of I)t(i)&&e.push(i);return e}export{N as $};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Login-CBpAitxd.js b/luci-app-honk/root/etc/honk/dashboard/assets/Login-CBpAitxd.js
new file mode 100644
index 000000000..c0c78fa17
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Login-CBpAitxd.js
@@ -0,0 +1,2 @@
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./LoginShowcase-CwRzXrsa.js","./vendor-react-Bf71BWbF.js","./index-CXHBmSa5.js","./index-BMPxGQXj.css"])))=>i.map(i=>d[i]);
+import{u as z,a as W,e as X,d as I,A as L,i as Y,b as ee,s as se,r as ne,w as te,n as B,c as re,f as oe,L as C,h as ie,g as ae,S as le,l as ce,E as H,j as ue,I as de,T as b,B as ge,k as me,_ as pe}from"./index-CXHBmSa5.js";import{r as u,j as s}from"./vendor-react-Bf71BWbF.js";import{D as P,s as fe,d as he,a as xe,o as we}from"./auth-BGnwk8Hi.js";function ke(n,r,o,a){return n.some(t=>t.id===r&&B(t.api)===B(o))?n.map(t=>t.id===r?{...t,token:a.trim()}:t):null}const ye=/^[A-Za-z0-9_.-]{1,64}$/;function je(n,r,o,a){const t={};r?ye.test(r)||(t.username="login.badUsername"):t.username="login.usernameRequired";const l=[...o].length;return l?n==="setup"&&l<8?t.password="login.passwordShort":l>128||new TextEncoder().encode(o).length>512?t.password="login.passwordLong":n==="setup"&&o!==a&&(t.confirm="login.mismatch"):t.password="login.passwordRequired",t}function ve(n){return n instanceof L?n.code==="invalid_credentials"?{key:"login.invalidCredentials"}:n.code==="setup_required"?{key:"login.needsSetup",switchTo:"setup"}:n.code==="setup_already_completed"?{key:"login.alreadySetUp",switchTo:"login"}:n.code==="permission_denied"?{key:"login.setupPeer"}:n.code==="rate_limited"?{key:"login.rateLimited",params:{n:n.retryAfter??60}}:null:null}function be(n){return n instanceof SyntaxError?!0:n instanceof L&&(n.status===404||n.status===401||n.status===403)}async function Se(n,r){try{return fe(await he(n,r))}catch(o){if(!be(o))throw o;return!(o instanceof L)||o.status!==404||await xe(n,r)?"token":"no-api"}}function Te(n,r,o){try{const{profiles:a,activeId:t}=ne(),l=ke(a,n,r,o);if(!l)return"login.stale";te({profiles:l,activeId:t})}catch{return"settings.saveError"}return null}async function Ee(n,r,o,a){let t;try{t=await we(r,o,a)}catch(l){return ve(l)??{error:l}}try{se(n,r,t.token,t.expires_at)}catch{return{key:"settings.saveError"}}return null}function Ne(n,r){const{kind:o,failure:a,attempt:t,ended:l,rejected:h}=n;return o==="no-api"?null:a!==null?{tone:"negative",text:typeof a=="string"?a:r(a.key,a.params),focus:!0,id:t}:l?{tone:"informative",text:r("login.sessionEnded"),focus:!1,id:0}:h&&o==="token"?{tone:"negative",text:r("login.rejected"),focus:!1,id:0}:null}function Ae(n,r,o,a){const t=z(),l=W(),[h]=u.useState(()=>X(n,r)),[c,w]=u.useState(null),[k,y]=u.useState({attempt:0,error:null});u.useEffect(()=>{const i=new AbortController;return Se(r,i.signal).then(g=>w(g),g=>{i.signal.aborted||y(m=>({...m,error:g instanceof Error?g:new Error(String(g))}))}),()=>i.abort()},[r,k.attempt]);const[p,d]=u.useState(""),e=Y(r),[x,j]=u.useState(e?P.username:""),[f,S]=u.useState(e?P.password:""),[D,R]=u.useState(""),[T,K]=u.useState(!1),[U,q]=u.useState(!1),[E,F]=u.useState({}),[V,v]=u.useState(null),[Z,Q]=u.useState(0),N=(i,g)=>m=>{g(m),E[i]&&F(({[i]:Ce,...J})=>J)},$=()=>{if(!p.trim())return;const i=Te(n,r,p);i?v({key:i}):location.reload()},G=async i=>{const g=je(i,x,f,D);if(F(g),Object.keys(g).length)return;q(!0);const m=await Ee(n,r,i,{username:x,password:f});if(!m){location.reload();return}if(q(!1),"error"in m){v(t("login.failed",{error:ee(m.error,t)}));return}m.switchTo&&(w(m.switchTo),R("")),v(m)},A=c==="setup"||c==="login",_=i=>E[i]?t(E[i]):void 0;return{kind:c,discoveryError:k.error,retryDiscovery:()=>y(i=>({attempt:i.attempt+1,error:null})),title:t(c==="no-api"?"login.noApiTitle":c==="setup"?"login.setupTitle":c==="token"?"login.title":"login.passwordTitle"),note:c==="no-api"?t("login.noApiNote"):c==="setup"?t("login.setupNote",{backend:o}):c==="login"?t("login.connectedTo",{backend:o}):t("login.note",{backend:o}),demoNote:e&&c==="login"?t("login.demoNote",P):null,alert:Ne({kind:c,failure:V,attempt:Z,ended:h,rejected:a},t),busy:U,token:p,setToken:d,username:x,setUsername:N("username",j),usernameError:_("username"),password:f,setPassword:N("password",S),passwordError:_("password"),confirm:D,setConfirm:N("confirm",R),confirmError:_("confirm"),submit:()=>{U||c==="no-api"||(v(null),Q(i=>i+1),A?G(c):$())},canSubmit:c!=="no-api"&&(A||!!p.trim()),secretType:T?"text":"password",toggle:()=>K(i=>!i),toggleText:t(A?T?"login.hidePassword":"login.showPassword":T?"settings.hideToken":"settings.showToken"),guideHref:I(l),requirementsHref:I(l,"no-native-api")}}function M({className:n,...r}){return s.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",width:10,height:10,viewBox:"0 0 12 12","aria-hidden":"true",focusable:"false",className:re("rp-icon rp-link-out",n),...r,children:s.jsx("path",{fill:"currentColor",d:"m10.08887,1h-5.51074c-.50293,0-.91113.4082-.91113.91113s.4082.91113.91113.91113h3.31055L1.35547,9.35547c-.35645.35645-.35645.93262,0,1.28906.17773.17773.41113.2666.64453.2666s.4668-.08887.64453-.2666l6.5332-6.5332v3.31055c0,.50293.4082.91113.91113.91113s.91113-.4082.91113-.91113V1.91113c0-.50293-.4082-.91113-.91113-.91113Z"})})}const _e=u.lazy(()=>pe(()=>import("./LoginShowcase-CwRzXrsa.js"),__vite__mapDeps([0,1,2,3]),import.meta.url)),O=s.jsx("div",{className:"rp-login-showcase","aria-hidden":"true"});function Re({profileId:n,api:r,backend:o,rejected:a,lang:t,pickLang:l,dark:h,themeLabel:c,toggleScheme:w,wordmark:k,error:y,onRetry:p}){const d=z(),e=Ae(n,r,o,a),x=oe("(min-width: 1024px)"),j={shown:e.secretType==="text",label:e.toggleText,onToggle:e.toggle},f=s.jsxs("div",{className:"rp-login-links",children:[s.jsx(C,{appearance:"link",href:ie("settings"),children:d("login.settings")}),s.jsxs(C,{appearance:"link",href:e.guideHref,external:!0,children:[d("shell.guide"),s.jsx(M,{})]})]});return s.jsxs("div",{className:"rp-login-page",children:[s.jsxs("div",{className:"rp-login-pane",children:[s.jsxs("header",{className:"rp-login-controls",children:[s.jsx(ae,{lang:t,pickLang:l}),s.jsx(le,{dark:h,label:c,toggle:w})]}),s.jsxs("main",{className:"rp-login-column",children:[s.jsxs("div",{className:"rp-login-brand",children:[s.jsx("img",{src:ce,alt:""}),s.jsx("span",{className:"rp-brand-text",children:s.jsx("span",{children:k})})]}),s.jsxs("div",{className:"rp-login-head",children:[s.jsx("h1",{className:"rp-h1",children:e.title}),e.note&&s.jsx("p",{className:"rp-login-note",children:e.note})]}),s.jsx(H,{error:y,onRetry:p}),e.kind===null?e.discoveryError?s.jsxs(s.Fragment,{children:[s.jsx(H,{error:e.discoveryError,onRetry:e.retryDiscovery}),f]}):s.jsx(ue,{}):s.jsxs(s.Fragment,{children:[s.jsxs("form",{className:"rp-login",onSubmit:S=>{S.preventDefault(),e.submit()},children:[e.alert&&s.jsx(de,{tone:e.alert.tone,takeFocus:e.alert.focus,children:e.alert.text},e.alert.id),e.kind==="no-api"?s.jsxs(C,{appearance:"link",href:e.requirementsHref,external:!0,children:[d("login.requirements"),s.jsx(M,{})]}):e.kind==="token"?s.jsx(b,{label:d("login.token"),name:"token",type:e.secretType,value:e.token,autoComplete:"off",onChange:e.setToken,reveal:j}):s.jsxs(s.Fragment,{children:[s.jsx(b,{label:d("login.username"),name:"username",value:e.username,autoComplete:"username",spellCheck:"false",error:e.usernameError,onChange:e.setUsername}),s.jsx(b,{label:d("login.password"),name:"password",type:e.secretType,value:e.password,autoComplete:e.kind==="setup"?"new-password":"current-password",description:e.kind==="setup"?d("login.passwordRule"):void 0,error:e.passwordError,onChange:e.setPassword,reveal:j}),e.kind==="setup"&&s.jsx(b,{label:d("login.confirm"),name:"confirm",type:e.secretType,value:e.confirm,autoComplete:"new-password",error:e.confirmError,onChange:e.setConfirm})]}),e.kind!=="no-api"&&s.jsx(ge,{accent:!0,className:"rp-login-submit",type:"submit",isDisabled:!e.canSubmit,isPending:e.busy,children:d(e.kind==="setup"?"login.create":e.kind==="login"?"login.signIn":"login.submit")})]}),e.demoNote&&s.jsx("p",{className:"rp-login-note rp-login-account",children:e.demoNote}),f]})]})]}),x&&s.jsx(me,{fallback:O,children:s.jsx(u.Suspense,{fallback:O,children:s.jsx(_e,{})})})]})}export{Re as Login};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Login-CoF6Tj1K.js b/luci-app-honk/root/etc/honk/dashboard/assets/Login-CoF6Tj1K.js
deleted file mode 100644
index 4c26d27b8..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Login-CoF6Tj1K.js
+++ /dev/null
@@ -1 +0,0 @@
-import{r as l,j as n}from"./vendor-react-Bf71BWbF.js";import{u as U,e as H,A,s as J,a as Q,r as V,w as W,n as D,M as X,l as Y,E as ee,L as E,h as F,b as te,I as se,T as w,B as ne}from"./index-zQjLFfuj.js";import{s as re,d as oe,a as ie,o as ae}from"./auth-CPB25VPp.js";function le(s,o,a,d){return s.some(t=>t.id===o&&D(t.api)===D(a))?s.map(t=>t.id===o?{...t,token:d.trim()}:t):null}const ue=/^[A-Za-z0-9_.-]{1,64}$/;function ce(s,o,a,d){const t={};o?ue.test(o)||(t.username="login.badUsername"):t.username="login.usernameRequired";const e=[...a].length;return e?e<8?t.password="login.passwordShort":e>128||new TextEncoder().encode(a).length>512?t.password="login.passwordLong":s==="setup"&&a!==d&&(t.confirm="login.mismatch"):t.password="login.passwordRequired",t}function de(s){return s instanceof A?s.code==="invalid_credentials"?{key:"login.invalidCredentials"}:s.code==="setup_required"?{key:"login.needsSetup",switchTo:"setup"}:s.code==="setup_already_completed"?{key:"login.alreadySetUp",switchTo:"login"}:s.code==="permission_denied"?{key:"login.setupPeer"}:s.code==="rate_limited"?{key:"login.rateLimited",params:{n:s.retryAfter??60}}:null:null}function pe(s){return s instanceof SyntaxError?!0:s instanceof A&&(s.status===404||s.status===401||s.status===403)}async function ge(s,o){try{return re(await oe(s,o))}catch(a){if(!pe(a))throw a;return!(a instanceof A)||a.status!==404||await ie(s,o)?"token":"no-api"}}function me(s,o,a,d){const t=U(),[e]=l.useState(()=>H(s,o)),[i,m]=l.useState(null),[C,P]=l.useState({attempt:0,error:null});l.useEffect(()=>{const r=new AbortController;return ge(o,r.signal).then(u=>m(u),u=>{r.signal.aborted||P(c=>({...c,error:u instanceof Error?u:new Error(String(u))}))}),()=>r.abort()},[o,C.attempt]);const[f,q]=l.useState(""),[k,I]=l.useState(""),[y,M]=l.useState(""),[N,_]=l.useState(""),[x,B]=l.useState(!1),[L,v]=l.useState(!1),[b,R]=l.useState({}),[p,g]=l.useState(null),[K,z]=l.useState(0),j=(r,u)=>c=>{u(c),b[r]&&R(({[r]:h,...G})=>G)},O=()=>{if(f.trim()){try{const{profiles:r,activeId:u}=V(),c=le(r,s,o,f);if(!c){g({key:"login.stale"});return}W({profiles:c,activeId:u})}catch{g({key:"settings.saveError"});return}location.reload()}},Z=async r=>{const u=ce(r,k,y,N);if(R(u),!Object.keys(u).length){v(!0);try{const c=await ae(o,r,{username:k,password:y});try{J(s,o,c.token,c.expires_at)}catch{v(!1),g({key:"settings.saveError"});return}location.reload()}catch(c){v(!1);const h=de(c);h?.switchTo&&(m(h.switchTo),_("")),g(h??t("login.failed",{error:Q(c,t)}))}}},S=i==="setup"||i==="login",$=i==="no-api"?null:p!==null?{tone:"negative",text:typeof p=="string"?p:t(p.key,p.params),focus:!0,id:K}:e?{tone:"informative",text:t("login.sessionEnded"),focus:!1,id:0}:d&&i==="token"?{tone:"negative",text:t("login.rejected"),focus:!1,id:0}:null,T=r=>b[r]?t(b[r]):void 0;return{kind:i,discoveryError:C.error,retryDiscovery:()=>P(r=>({attempt:r.attempt+1,error:null})),title:t(i==="no-api"?"login.noApiTitle":i==="setup"?"login.setupTitle":i==="token"?"login.title":"login.passwordTitle"),note:i==="no-api"?t("login.noApiNote"):i==="setup"?t("login.setupNote",{backend:a}):i==="login"?null:t("login.note",{backend:a}),alert:$,busy:L,token:f,setToken:q,username:k,setUsername:j("username",I),usernameError:T("username"),password:y,setPassword:j("password",M),passwordError:T("password"),confirm:N,setConfirm:j("confirm",_),confirmError:T("confirm"),submit:()=>{L||i==="no-api"||(g(null),z(r=>r+1),S?Z(i):O())},canSubmit:i!=="no-api"&&(S||!!f.trim()),secretType:x?"text":"password",toggle:()=>B(r=>!r),toggleText:t(S?x?"login.hidePassword":"login.showPassword":x?"settings.hideToken":"settings.showToken")}}function ke({profileId:s,api:o,backend:a,rejected:d}){const t=U(),e=me(s,o,a,d),i={shown:e.secretType==="text",label:e.toggleText,onToggle:e.toggle};return n.jsxs(X,{isOpen:!0,locked:!0,narrow:!0,hideTitle:!0,title:e.title,children:[n.jsxs("div",{className:"rp-login-brand",children:[n.jsx("img",{src:Y,alt:""}),n.jsx("span",{className:"rp-brand-text",children:n.jsx("span",{children:"doona"})}),n.jsx("h2",{className:"rp-h3",children:e.title})]}),n.jsx("form",{className:"rp-login",onSubmit:m=>{m.preventDefault(),e.submit()},children:e.kind===null?e.discoveryError?n.jsxs(n.Fragment,{children:[n.jsx(ee,{error:e.discoveryError,onRetry:e.retryDiscovery}),n.jsx("div",{className:"rp-toolbar",children:n.jsx(E,{appearance:"link",href:F("settings"),children:t("login.settings")})})]}):n.jsx(te,{}):n.jsxs(n.Fragment,{children:[e.note&&n.jsx("span",{className:"rp-label",children:e.note}),e.alert&&n.jsx(se,{tone:e.alert.tone,takeFocus:e.alert.focus,children:e.alert.text},e.alert.id),e.kind==="no-api"?n.jsx(E,{appearance:"link",href:"https://github.com/Zakkaus/doona#native-api-requirement",children:t("login.requirements")}):e.kind==="token"?n.jsx(w,{label:t("login.token"),name:"token",type:e.secretType,value:e.token,autoComplete:"off",onChange:e.setToken,reveal:i}):n.jsxs(n.Fragment,{children:[n.jsx(w,{label:t("login.username"),name:"username",value:e.username,autoComplete:"username",spellCheck:"false",error:e.usernameError,onChange:e.setUsername}),n.jsx(w,{label:t("login.password"),name:"password",type:e.secretType,value:e.password,autoComplete:e.kind==="setup"?"new-password":"current-password",description:e.kind==="setup"?t("login.passwordRule"):void 0,error:e.passwordError,onChange:e.setPassword,reveal:i}),e.kind==="setup"&&n.jsx(w,{label:t("login.confirm"),name:"confirm",type:e.secretType,value:e.confirm,autoComplete:"new-password",error:e.confirmError,onChange:e.setConfirm})]}),n.jsxs("div",{className:"rp-toolbar",children:[e.kind!=="no-api"&&n.jsx(ne,{accent:!0,type:"submit",isDisabled:!e.canSubmit,isPending:e.busy,children:t(e.kind==="setup"?"login.create":e.kind==="login"?"login.signIn":"login.submit")}),n.jsx(E,{appearance:"link",href:F("settings"),children:t("login.settings")})]})]})})]})}export{ke as Login};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/LoginShowcase-CwRzXrsa.js b/luci-app-honk/root/etc/honk/dashboard/assets/LoginShowcase-CwRzXrsa.js
new file mode 100644
index 000000000..1a7149981
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/LoginShowcase-CwRzXrsa.js
@@ -0,0 +1 @@
+import{j as N,r as B}from"./vendor-react-Bf71BWbF.js";import{u as W1,f as j1,aJ as K1}from"./index-CXHBmSa5.js";function N1({label:r,className:a,isDisabled:m,ref:e,canvasRef:l}){return N.jsx("button",{ref:e,type:"button",className:a,"aria-label":r,disabled:m,children:N.jsx("canvas",{ref:l})})}const U1=[["ink","M657 1228c-12-4-23-14-28-26-1-4-2-4-4-4-22 4-36 3-49-3-11-6-18-16-20-27-2-11 3-23 12-34 3-3 6-6 6-6 0 0-7-1-15-1-34-2-70-7-100-14-49-12-98-36-134-67l-5-4-12 4c-20 7-36 9-60 9-21 0-43-4-57-10-13-5-25-16-30-25-5-10-4-23 3-34 4-6 16-18 24-22l6-4-3-8c-2-5-2-9-2-12 1-6 5-15 9-18 4-5 16-13 21-14 3-1 5-2 6-2 0-1-1-6-3-12-21-73-6-145 45-212l7-10-12-2c-15-1-23-3-34-7-24-9-40-29-40-49 0-19 7-34 36-72 15-21 27-39 35-54 11-19 10-17 5-28-2-4-5-11-6-14-2-8-3-32-1-43 4-28 18-59 42-90l3-5-6-4c-11-9-20-21-23-32-2-6-2-9-2-17 1-9 1-10 4-18 6-11 15-20 29-27 14-7 24-10 47-15 1 0 3-3 7-11 19-37 51-71 88-94 12-8 32-18 44-22 10-3 29-8 33-8 1 0 5-2 8-5 11-8 25-14 39-16 12-2 49-1 63 2 21 4 34 9 45 19 8 7 10 9 15 18 4 7 4 7 13 12 34 18 63 46 86 81 10 16 20 38 26 57 4 12 8 34 10 48 2 13 2 43 0 56l-1 10 6 7c8 8 14 19 18 28 3 9 4 24 2 33-3 14-14 27-29 35-9 5-19 7-31 8l-9 1 0 8c0 4 0 15 0 25 0 16-1 31-5 47l0 3 14 0c27 0 58 5 83 14 21 9 51 25 68 39 3 2 6 5 7 5 0 1 6-2 14-6 27-14 49-17 69-11 26 8 38 34 27 64-2 5-3 9-3 10 0 0 4 1 8 3 14 7 24 19 29 34 8 22 0 45-24 73l-5 6 3 9c6 26 8 63 5 89-2 14-7 33-12 48-9 22-26 52-43 72-10 13-34 36-47 46-28 22-59 39-93 52-16 7-44 16-47 16-1 0-1 1-1 3 9 31 7 61-3 81-8 16-19 27-33 34-9 4-14 5-25 5-15 0-28-4-39-13l-6-5-7 6c-9 7-18 13-26 16-9 3-27 4-35 1z"],["paper","M582 1098c-44-2-79-6-117-16-55-14-102-41-141-81-42-43-67-93-75-148-2-14-1-43 1-56 6-30 16-57 32-82 8-12 24-33 32-42 6-7 7-7 17-10 58-18 110-56 126-92 2-5 2-9 3-16 1-14-2-21-15-33-13-14-21-24-33-39-18-26-28-35-45-43-11-5-21-7-33-7-13 0-23 2-33 7-6 3-9 3-9 3-4-6-4-28-2-42 5-23 18-49 37-73 14-18 37-39 56-53 5-4 6-4 11-4 41 1 105 13 154 28 32 9 72 25 104 42 18 9 51 27 66 37 8 5 8 5 11 13 7 16 13 37 16 56 2 11 2 41 1 54-4 39-19 74-44 104-8 9-10 14-9 20 1 5 7 10 13 12 7 2 14-1 24-11 10-11 22-29 32-48 3-5 4-7 6-7 2-1 14-1 27-1 22 0 24 0 37 2 34 8 68 24 98 48 13 11 15 12 20 12 5 0 7-1 16-7 22-14 41-21 53-18 13 3 16 15 7 32-2 5-6 11-8 15-4 8-4 14 0 19 4 5 7 6 17 7 15 1 23 5 27 14 3 6 3 15 0 22-2 6-10 18-20 30-9 11-11 15-8 24 3 10 6 33 7 52 0 26-2 47-10 70-18 53-57 101-111 135-40 25-87 43-144 54-66 14-132 19-194 17z"],["ink","M517 445c-7-2-13-6-18-12-7-7-9-14-9-25 0-7 0-8 3-15 7-13 17-21 31-22 23-1 43 18 41 40-2 19-17 33-36 35-4 0-9-1-12-1z"],["yellow","M541 220c-13-3-27-7-41-9-6-1-14-3-17-3l-5-1 2-6c3-15 13-40 23-59 20-39 43-66 64-73 11-3 56-1 74 4 7 1 13 4 17 7 3 3 3 4-1 4-5 0-17 4-24 7-35 18-62 59-79 118-2 8-4 14-4 14 0 0-4-1-9-3z"],["yellow","M446 203c-4-1-19-1-35-2-16 0-29 0-29-1 0-1 6-12 12-20 22-34 53-62 87-78 10-5 32-13 33-12 0 0-2 3-6 8-19 27-38 69-47 102-1 4-1 4-5 4-3 0-7-1-10-1z"],["yellow","M569 226c13-58 39-102 70-119 14-7 21-6 40 1 53 23 96 73 113 132 9 29 11 67 7 95-71-43-149-81-230-109z"],["yellow","M780 426c-1-2-5-19-5-19 0-1 3 0 8 0 6 0 8 0 10-2 5-4 3-6-21-21-50-32-74-46-109-63-71-36-143-57-225-67-48-6-99-5-107 1-4 3-5 5-2 7 1 2 3 2 10 3l8 0-4 4c-3 3-9 8-13 12l-9 8-4-2c-6-4-13-11-16-17-3-5-4-12-3-17 2-8 11-17 22-22 22-10 60-14 101-12 63 3 121 16 167 36 71 31 145 67 214 105 17 10 27 31 23 45-1 5-6 12-10 15-6 4-15 6-25 7-8 0-10 0-10-1z"],["yellow","M251 640c-19-4-32-16-32-29 0-10 5-19 23-43 26-34 37-50 50-75 6-12 9-17 13-20 12-11 29-13 45-7 11 5 17 10 37 36 9 13 19 25 24 30 5 5 10 10 12 13 2 3 2 5 2 10 0 5-1 8-4 12-17 29-73 61-123 71-14 3-38 4-47 2z"],["yellow","M226 1028c-12-1-24-5-31-10-12-8-13-16-2-27 5-5 19-13 30-17 7-3 11-6 11-8 0-3-1-5-8-9-7-6-10-10-10-14 0-4 1-5 4-8 2-2 6-4 9-5 3-1 5-2 5-2 1 0 4 7 8 14 15 29 28 49 49 72 4 5 7 8 7 9-1 1-21 5-29 6-13 1-31 1-43-1z"],["yellow","M663 1201c-7-4-9-12-7-24 1-7 1-8 0-10-3-4-7-4-15-1-18 7-40 10-48 7-5-2-8-6-8-11 0-7 8-16 29-30l10-7 19 0c22-1 52-4 78-7 18-3 57-9 65-11 6-2 11-1 14 1 2 3 4 7 5 20 4 39-13 70-39 68-9-1-16-5-29-17-14-12-14-12-27 1-11 11-20 18-28 21-7 3-15 3-19 0z"]],U={width:940,height:1192},K=1.4,R=52,Z=72,f1=500,V1=250,F=22,Y=22,i1=Y+2,l1=16,u1=12,X1=56,A1=17,E=9,S1=18,q=1/120,h1=1500,e1=430,C=48,J1=e1*e1/(2*h1),H1=Math.max(2.2*R,R+J1+4),B1=200,_1=B1*h1/(2*e1),Q=.84*R*U.width/U.height/2,d1=.84*R/2;function G1(r,a,m){let e=0;for(;r>=1e3&&e1?1:0))+" "+a[e]}function G(r){return G1(r,["MB","GB","TB","PB"],2)}function I1(r){return r<6?[100,150,200,300,450,650][r]:[1,1.5,2.5,4,6][(r-6)%5]*Math.pow(10,3+Math.floor((r-6)/5))}function q1(r){const a=I1(r);return a<1e3?a+" Mbps":G1(a,["Mbps","Gbps","Tbps","Pbps"],1).replace(".0 "," ")}function D1(r){const a=Math.pow(.9,r);return{speed:_1-(_1-110)*a,gap:H1+(205-H1)*a,space:B1+70*a,swing:r<6?0:34*(1-Math.pow(.8,r-5)),drift:r>=6}}function Q1(r){return(Math.floor(r*1e3/f1)+3)%4}function Y1(r,a,m={}){const e=Z*U.width/U.height,l=Math.max(X1,m.board??0),I=Math.floor(r-2*(u1+l1)-l-i1-Y-e),P=Math.max(120,m.row??0,Math.min(V1,I)),c=l+i1+P+Y+e,f=Math.min(1,(r/2-u1)/(c/2+l1)),g=-2*F,M=g-12,u=-Z,b=40,h=Math.round(a/2-(u+b+4)/2),v=Math.round(r/2),w=Math.round(v-c/2),A=w+l+i1;return{cx:v,post:w,board:l,x:A,bar:P,ground:h,top:h+g,label:h+M,head:h+u,sign:h+M-(m.cap??12)+.75,rail:h+g+(F-E)/2,start:h+b,duck:A+P+Y+e/2,reach:Math.round(c/2+l1),shrink:f,text:(r-2*u1)/f}}function Z1(r,a,m){const e=a.getContext("2d");if(!e)return{setText(){},destroy(){}};const l=matchMedia("(prefers-reduced-motion: reduce)"),I=document.documentElement,P=U1.map(([t,n])=>[t,new Path2D(n)]);let c,f="",g=g1(),M=1,u=0,b=0,h=0,v=0,w=0,A=0,S=0,y=[],H=0,V=0,_=0,p1=0,t1=0,z=!1,x=0,X=0,n1=0,$=0,J=0,o1=!0,s1=0,r1=0;const m1=performance.now();function g1(){const t=getComputedStyle(r),n=s=>t.getPropertyValue(s).trim();return f=t.fontFamily,{ink:n("--rp-mark-ink"),paper:n("--rp-mark-paper"),yellow:n("--rp-mark-yellow"),text:n("--rp-text"),sub:n("--rp-subtle"),accent:n("--rp-accent"),wall:n("--rp-negative"),base:n("--rp-base"),bar:n("--rp-positive")}}function w1(){M=(window.devicePixelRatio||1)*K,a.width=Math.round(a.clientWidth*M/K),a.height=Math.round(a.clientHeight*M/K),u=a.clientWidth/K,b=a.clientHeight/K,h=Math.round(b*.84),v=Math.round(u*.3)}function M1(t){const n=D1(_),s=40+n.gap/2+n.swing,i=h-30-n.gap/2-n.swing,d=y[y.length-1];let o=s+Math.random()*(i-s);if(d){const L=(n.gap-2*d1)/2+220*(n.space-C-2*Q)/n.speed-2*n.swing;n.drift&&Math.random()<.6&&(o=d.c0<(s+i)/2?i:s),o=Math.max(d.c0-L,Math.min(d.c0+L,o))}o=Math.max(s,Math.min(i,o));const p=n.swing*(Math.random()<.5?1:0);y.push({x:t,ox:t,gap:n.gap,c0:o,c:o,oc:o,a:p,f:p?Math.min(3,110/p):0,ph:Math.random()*6.3,done:!1})}function x1(){w=A=b*.42,S=H=_=p1=t1=x=$=0,y=[],M1(u+10)}function b1(){x=performance.now(),V=Math.max(V,H),m(G(H),G(V)),window.clearTimeout(s1),s1=window.setTimeout(()=>W(),950)}function z1(t){const n=D1(_);J+=t,A=w,S=Math.min(700,S+h1*t),w+=S*t,wv-Q&&(w-d1s.c+s.gap/2)&&b1();y[y.length-1].xs.x>-C),!x&&w+R/2-3>h&&(w=h-R/2+3,b1())}function D(t,n){e.beginPath(),n(),e.fillStyle=t,e.fill(),e.stroke()}function y1(t,n,s,i,d=!1){const o=s/U.height;e.save(),e.translate(t,n),e.rotate(i),e.scale(d?o:-o,o),e.translate(-628,-634);for(const[p,L]of P)e.fillStyle=g[p],e.fill(L,"evenodd");e.restore()}function O1(t,n,s,i,d){for(const[o,p]of[[t+10,t+5],[t+n-10,t+n-5]])D(g.paper,()=>{e.moveTo(o-2.5,s),e.lineTo(o+2.5,s),e.lineTo(p+2.5,d),e.lineTo(p-2.5,d),e.closePath()});D(g.yellow,()=>e.roundRect(t,i,n,E,2)),e.save(),e.beginPath(),e.roundRect(t,i,n,E,2),e.clip(),e.fillStyle=g.ink;for(let o=t-E;oe.roundRect(t,s,n,A1,3))}function k(t,n,s,i,d,o){e.fillStyle=i,e.font=`${d?600:500} ${d??13}px ${f}`,e.fillText(t,n,s,o)}function C1(t){return Math.round(t*M)/M}function W(t=1){if(e.setTransform(M,0,0,M,0,0),e.clearRect(0,0,u,b),!c||!u)return;const n=g;if(e.lineWidth=1.5,e.strokeStyle=n.ink,e.lineJoin="round",e.textAlign="center",!z){e.font=`600 11px ${f}`;const s=Math.ceil(e.measureText(c.status).width)+16;e.font=`600 15px ${f}`;const i=e.measureText([...c.loading][0]??"").actualBoundingBoxAscent,d=e.measureText(c.progress).width,o=Y1(u,b,{board:s,row:Math.ceil(e.measureText(c.loading+"...").width+S1+d),cap:i});e.save(),e.translate(o.cx,b/2),e.scale(o.shrink,o.shrink),e.translate(-o.cx,-b/2),e.fillStyle=n.sub,e.fillRect(o.cx-o.reach,o.ground,2*o.reach,1.5),O1(o.post,o.board,o.sign,o.rail,o.ground),D(n.paper,()=>e.roundRect(o.x,o.top,o.bar,F,F/2)),e.fillStyle=n.bar,e.beginPath(),e.roundRect(o.x+4,o.top+4,(o.bar-8)*.97,F-8,(F-8)/2),e.fill();const p=Q1(l.matches?0:(performance.now()-m1)/1e3);e.textAlign="right",k(c.progress,o.x+o.bar,o.label,n.text,15),e.textAlign="left",k(c.loading+"...".slice(0,p),o.x,o.label,n.text,15,o.bar-S1-d),e.textAlign="center",e.textBaseline="middle",k(c.status,o.post+o.board/2,o.sign+A1/2+.5,n.ink,11,o.board-16),e.textBaseline="alphabetic",y1(o.duck,o.ground-Z/2,Z,-.06,!0),l.matches||k(c.start,o.cx,o.start,n.sub,void 0,Math.min(360,o.text)),e.restore();return}e.fillStyle=n.sub,e.fillRect(0,h,u,1.5);for(const s of y){const i=C1(s.ox+(s.x-s.ox)*t),d=s.oc+(s.c-s.oc)*t,o=d-s.gap/2,p=d+s.gap/2;for(const[L,$1]of[[0,o],[p,h]]){D(n.wall,()=>e.rect(i,L-2,C,$1-L+2)),e.fillStyle=n.base;const j=!L;for(let c1=1,O=(j?o:p)+(j?-12:12);O>1&&Oe.roundRect(u/2-150,16,300,92,8)),k(c.result(G(H)),u/2,46,n.text,16),k(c.best(G(Math.max(V,H))),u/2,70,n.sub),performance.now()-x>900&&k(c.restart,u/2,94,n.sub)):(D(n.base,()=>e.roundRect(u/2-70,18,140,52,8)),k(G(H),u/2,40,n.text,16),k(q1(_),u/2,60,J-t1<1.2&&_?n.accent:n.sub)),e.strokeStyle=n.ink,y1(v,A+(w-A)*t,R,Math.max(-.35,Math.min(.5,S/900)))}function F1(t){for(X=0,$+=Math.min(.1,(t-(n1||t))/1e3),n1=t;$>=q&&!x;)z1(q),$-=q;W(x?1:$/q),T()}function T(){if(window.clearTimeout(r1),l.matches&&(z=!1),!z||x||l.matches||document.hidden||!o1){n1=0,!z&&!l.matches&&!document.hidden&&o1&&(r1=window.setTimeout(T,f1-(performance.now()-m1)%f1+5)),W();return}X||(X=requestAnimationFrame(F1))}function a1(t){l.matches||x&&!t&&performance.now()-x<900||((!z||x||t)&&(z=!0,x1()),S=-e1,T())}const T1=t=>{t.button||(t.preventDefault(),r.focus({preventScroll:!0,focusVisible:!1}),a1(!1))},k1=t=>{t.ctrlKey||t.metaKey||t.altKey||(t.key===" "||t.key==="r"||t.key==="R")&&(t.preventDefault(),t.repeat||a1(t.key!==" "))},E1=t=>{t.detail===0&&a1(!1)},R1=()=>{g=g1(),W()};r.addEventListener("pointerdown",T1),r.addEventListener("keydown",k1),r.addEventListener("click",E1),document.addEventListener("visibilitychange",T),l.addEventListener("change",T);const v1=new ResizeObserver(()=>{w1(),T()});v1.observe(a);const L1=new IntersectionObserver(t=>{o1=t[t.length-1].isIntersecting,T()});L1.observe(a);const P1=new MutationObserver(R1);return P1.observe(I,{attributes:!0,attributeFilter:["data-scheme","data-family","data-flavour"]}),w1(),x1(),T(),{setText(t){c=t,R1();const n=[t.loading,".",t.progress,t.status,t.start,t.restart,t.result(G(0)),t.best(G(0))].join("");Promise.all([500,600].map(s=>document.fonts.load(`${s} 16px ${f}`,n))).then(()=>{c===t&&W()},()=>{})},destroy(){c=void 0,cancelAnimationFrame(X),window.clearTimeout(s1),window.clearTimeout(r1),r.removeEventListener("pointerdown",T1),r.removeEventListener("keydown",k1),r.removeEventListener("click",E1),document.removeEventListener("visibilitychange",T),l.removeEventListener("change",T),v1.disconnect(),L1.disconnect(),P1.disconnect()}}}function ne(){const r=W1(),a=j1("(prefers-reduced-motion: reduce)"),m=B.useRef(null),e=B.useRef(null),l=B.useRef(null),[I,P]=B.useState(null),c=B.useMemo(()=>({loading:r("login.gameLoading"),progress:r("login.gameProgress"),status:r("login.gameStatus"),start:r("login.gameStart"),restart:r("login.gameRestart"),result:f=>r("login.gameResult",{amount:f}),best:f=>r("login.gameBest",{amount:f})}),[r]);return B.useEffect(()=>{const f=Z1(m.current,e.current,(g,M)=>P({amount:g,best:M}));return l.current=f,()=>{f.destroy(),l.current=null}},[]),B.useEffect(()=>l.current?.setText(c),[c]),N.jsxs("aside",{className:"rp-login-showcase","aria-hidden":a||void 0,children:[N.jsx(N1,{ref:m,canvasRef:e,className:"rp-login-game",label:r("login.gameLabel"),isDisabled:a}),N.jsx(K1,{"aria-live":"polite",children:I&&r("login.gameOver",I)})]})}export{ne as default};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Logs-JK5xuRFC.js b/luci-app-honk/root/etc/honk/dashboard/assets/Logs-JK5xuRFC.js
deleted file mode 100644
index 154c8d757..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Logs-JK5xuRFC.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import{j as a,r as v}from"./vendor-react-Bf71BWbF.js";import{aB as B,u as M,X as O,_ as R,as as P,dn as L,B as W,dp as q,bm as k,dq as C,ax as H,V as N,W as _,ah as I,$ as V,aq as G,bg as J,dr as U,av as $,at as S,aT as X,T as z,cl as K,aw as Q,E as Y}from"./index-zQjLFfuj.js";import{F as Z}from"./FactStrip-vcLr7nBw.js";import{u as ee,h as te,C as se,t as ae}from"./layout-B3T-zLsm.js";import{D as re}from"./Table-DLlwyNFJ.js";import{A as oe}from"./ActionGroup-C-LVMOvQ.js";import{a as ne,L as le}from"./logs-KkruktUh.js";import{d as ie,e as ce}from"./files-BxEOxSF8.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";function ue({label:e,rows:t,columns:o}){const r=B(),{ref:s,tip:h,show:l,hide:p}=ee();return a.jsxs("div",{className:"rp-heatmap rp-chart-hover",ref:s,onPointerLeave:p,role:"group","aria-label":e,"aria-describedby":r,style:{"--cols":o.length},children:[t.map(n=>{const c=Math.max(...n.counts);return a.jsxs("div",{className:"row",children:[a.jsx("div",{className:"head",children:n.label}),a.jsx("div",{className:"cells",children:n.counts.map((b,f)=>a.jsx("span",{className:"cell t"+te(b,c),style:{"--tone":n.color},onPointerMove:g=>l(g,[n.titles[f]]),role:"img","aria-label":n.titles[f]},f))})]},n.id)}),o.length>0&&a.jsxs("div",{className:"row times","aria-hidden":"true",children:[a.jsx("div",{className:"head"}),a.jsxs("div",{className:"ends",children:[a.jsx("span",{children:o[0]}),o.length>2&&a.jsx("span",{children:o[Math.floor(o.length/2)]}),o.length>1&&a.jsx("span",{children:o[o.length-1]})]})]}),a.jsx(se,{tip:h})]})}const A=new WeakMap;function D(e){let t=A.get(e);return t===void 0&&A.set(e,t=Date.parse(e.ts)),t}const y=["error","warn","info","debug","trace"];function ge(e,t,o,r=24){const s=o?y.indexOf(o):y.length-1,h=y.filter((u,x)=>t.includes(u)&&x<=s),l=e.map(D).filter(Number.isFinite);if(!l.length)return{rows:h.map(u=>({level:u,counts:[]})),buckets:[],width:0,busiest:null};const p=Math.min(...l),n=Math.max(...l),c=ae(p,n,r),b=c.length>1?c[1]-c[0]:Math.max(n-p,6e4),f=new Map(h.map(u=>[u,new Array(c.length).fill(0)])),g=new Array(c.length).fill(0),j=new Array(c.length).fill(0);for(const u of e){const x=D(u),T=f.get(u.level);if(!T||!Number.isFinite(x))continue;const w=Math.min(c.length-1,Math.floor((x-c[0])/b));T[w]++,g[w]++,u.level==="error"&&j[w]++}const i=u=>u.reduce((x,T,w)=>T>u[x]?w:x,0),m=j.reduce((u,x)=>u+x,0),d=i(m?j:g);return{rows:h.map(u=>({level:u,counts:f.get(u)})),buckets:c,width:b,busiest:{start:c[d],count:m?j[d]:g[d],errors:m}}}function de({records:e,offered:t,minimum:o,setMinimum:r}){const s=M(),h=O[R()],l=P(),p=v.useMemo(()=>ge(e,t,o),[e,t,o]),n=v.useMemo(()=>new Intl.DateTimeFormat(h,{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[h]),c=v.useCallback(i=>`${n.format(i)}–${n.format(i+p.width)}`,[n,p.width]),b=v.useMemo(()=>{const i=Object.keys(L).map(m=>{const d=s(L[m]);return[m,{text:d,label:a.jsxs(W,{quiet:!0,small:!0,className:m===o?"current":void 0,label:s(m===o?"log.chart.current":"log.chart.minimum",{level:d}),onPress:()=>r(m),children:[m===o&&a.jsx(q,{}),d]})}]});return new Map(i)},[o,r,s]),f=v.useMemo(()=>{const i={error:l.negative,warn:l.notice,info:l.info,debug:l.subtle,trace:l.muted},m=p.buckets.map(c);return{columns:p.buckets.map(d=>n.format(d)),rows:p.rows.map(d=>{const{text:u,label:x}=b.get(d.level);return{id:d.level,color:i[d.level],label:x,counts:d.counts,titles:d.counts.map((T,w)=>s("log.chart.cell",{time:m[w],level:u,n:T}))}})}},[p,c,n,b,l,s]);if(!e.length)return null;const g=p.busiest,j=g?g.errors?[{label:s("log.chart.errors"),value:s("log.chart.count",{n:g.errors}),icon:a.jsx(k,{}),tone:"negative"},{label:s("log.chart.peakErrors"),icon:a.jsx(C,{}),tint:"c1",value:c(g.start),caption:s("log.chart.count",{n:g.count})}]:[{label:s("log.chart.errors"),value:s("log.chart.count",{n:0}),icon:a.jsx(k,{}),tint:"c5"},{label:s("log.chart.peak"),icon:a.jsx(C,{}),tint:"c1",value:c(g.start),caption:s("log.chart.count",{n:g.count})}]:[];return a.jsxs("div",{className:"rp-chart-page",children:[a.jsx(Z,{facts:j}),a.jsx(H,{title:s("log.chart.title"),note:s("log.chart.sample",{n:e.length}),children:a.jsx(ue,{label:s("log.chart.title"),columns:f.columns,rows:f.rows})})]})}const E=["trace","debug","info","warn","error"],pe={trace:"muted",debug:"neutral",info:"info",warn:"warn",error:"err"},F=new WeakMap;function he(e,t,o){const r=F.get(e);if(r&&r.locale===t)return r.row;const s={id:e.id,timestamp:I(e.ts,t),iso:e.ts,levelText:N(L,e.level,o),tone:pe[e.level],target:e.target,gap:!1,message:e.message+(e.fields?" "+Object.entries(e.fields).map(([h,l])=>`${h}=${typeof l=="string"?l:JSON.stringify(l)}`).join(" "):"")};return F.set(e,{locale:t,row:s}),s}function me(e,t,o,r,s,h=new Set,l){const p=n=>!!l&&E.indexOf(n){const c=he(n,r,s);return h.has(n)?[{...c,id:`gap ${n.id}`,timestamp:"",iso:"",levelText:"",target:"",gap:!0,message:s("log.gap")},c]:[c]}),levels:t.map(n=>({id:n,label:p(n)?s("log.levelNotRecorded",{level:N(L,n,s)}):N(L,n,s)})),recordedText:l?s("log.recorded",{level:N(L,l,s)}):null,exportBase:`${o||"engine"}-log`}}function fe(e,t,o,r,s,h,l){return t?{tone:"err",text:l("log.disconnected")}:o?{tone:"neutral",text:l("log.paused",{n:r>s?`${_(s,h)}+`:r})}:{tone:e?"ok":"warn",text:l(e?"log.connected":"log.reconnecting")}}function xe(e,t=[]){return t.includes(e)?e:t.includes("info")?"info":t[0]}function ve(e,t,o){return[...e].reverse().flatMap(r=>{const s=`${r.ts} ${r.level.toUpperCase().padEnd(5)} ${r.target} ${r.message}${r.fields?" "+JSON.stringify(r.fields):""}`;return t.has(r)?[s,o("log.gap")]:[s]}).join(`
-`)+`
-`}const be=[];function je(){const e=M(),t=O[R()],o=V(),r=G(),[s,h]=v.useState("info"),l=v.useCallback(u=>h(u),[]),[p,n]=v.useState(""),[c,b]=v.useState(!1),f=J(p.trim()),g=o.data?.resources.logs,j=xe(s,g?.levels),i=ne({level:j,target:f,paused:c}),m=U(o.data?.resources.runtime_settings.available??!1).data?.log.level,d=v.useMemo(()=>me(i.records,g?.levels??[],r.data?.engine.name,t,e,i.gaps,m),[i.records,i.gaps,g,r.data,t,e,m]);return{...d,status:fe(i.connected,!!i.error,c,i.pending,le,t,e),records:i.records,offered:g?.levels??be,level:j??"",setLevel:l,target:p,setTarget:n,paused:c,setPaused:b,error:o.error??i.error,loading:!o.error&&!i.error&&!i.connected&&!i.records.length,clear:i.clear,retry:o.error?o.refetch:i.retry,export:()=>ie(ce(d.exportBase,"txt"),ve(i.records,i.gaps,e),"text/plain;charset=utf-8")}}function De(){const e=M(),t=je(),o=v.useMemo(()=>[{id:"ts",label:e("ui.time"),minWidth:200,grow:0,drop:2,render:r=>!r.gap&&a.jsx($,{className:"rp-code",text:r.iso,children:r.timestamp})},{id:"level",label:e("log.level"),minWidth:90,grow:0,drop:3,render:r=>!r.gap&&a.jsx(S,{small:!0,tone:r.tone,children:r.levelText})},{id:"target",label:e("log.target"),minWidth:160,grow:0,drop:1,render:r=>a.jsx("span",{className:"rp-code",children:r.target})},{id:"message",label:e("log.message"),minWidth:280,grow:3,isRowHeader:!0,render:r=>a.jsx($,{children:r.message})}],[e]);return a.jsxs("div",{className:"rp-page",children:[a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(X,{side:!0,label:e("log.level"),value:t.level,onChange:t.setLevel,items:t.levels}),a.jsx(z,{search:!0,label:e("log.target"),value:t.target,width:240,placeholder:e("log.targetPlaceholder"),onChange:t.setTarget}),a.jsx(K,{isSelected:t.paused,onChange:t.setPaused,children:e("log.pause")}),a.jsx(S,{small:!0,tone:t.status.tone,children:t.status.text}),t.recordedText&&a.jsx("span",{className:"rp-label",children:t.recordedText}),a.jsx("span",{className:"rp-grow"}),a.jsx(oe,{actions:[{id:"clear",label:e("log.clear"),isDisabled:!t.rows.length,onAction:t.clear},{id:"export",label:e("log.export"),icon:a.jsx(Q,{}),isDisabled:!t.rows.length,onAction:t.export}]})]}),a.jsx(Y,{error:t.error,onRetry:t.retry}),a.jsx(de,{records:t.records,offered:t.offered,minimum:t.level,setMinimum:t.setLevel}),a.jsx(re,{label:e("nav.logs"),stream:!0,rows:t.rows,height:640,loading:t.loading,empty:e("log.empty"),cols:o})]})}export{De as Logs};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Logs-bjF3zhK-.js b/luci-app-honk/root/etc/honk/dashboard/assets/Logs-bjF3zhK-.js
new file mode 100644
index 000000000..5cb31b98b
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Logs-bjF3zhK-.js
@@ -0,0 +1,3 @@
+import{j as a,r as b}from"./vendor-react-Bf71BWbF.js";import{aM as B,u as L,a2 as O,a as R,aB as P,dF as T,B as W,dG as q,bw as k,dH as C,aG as H,a0 as N,a1 as G,aq as I,a5 as J,ay as _,bq as V,dI as K,cQ as Q,dJ as U,aE as F,aC as E,aD as z,b2 as X,T as Y,cw as Z,aF as ee,E as te}from"./index-CXHBmSa5.js";import{F as se}from"./FactStrip-BgQ_tYB6.js";import{u as ae,h as re,C as oe,t as ne}from"./layout-BRLew_nj.js";import{D as le}from"./Table-D0NFHHNQ.js";import{A as ie}from"./ActionGroup-90AzAQje.js";import{d as ce,e as ge}from"./files-BxEOxSF8.js";import{r as ue}from"./recorder-DlDpPhd4.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";function de({label:e,rows:s,columns:r}){const n=B(),{ref:t,tip:m,show:l,hide:p}=ae();return a.jsxs("div",{className:"rp-heatmap rp-chart-hover",ref:t,onPointerLeave:p,role:"group","aria-label":e,"aria-describedby":n,style:{"--cols":r.length},children:[s.map(o=>{const c=Math.max(...o.counts);return a.jsxs("div",{className:"row",children:[a.jsx("div",{className:"head",children:o.label}),a.jsx("div",{className:"cells",children:o.counts.map((v,x)=>a.jsx("span",{className:"cell t"+re(v,c),style:{"--tone":o.color},onPointerMove:u=>l(u,[o.titles[x]]),role:"img","aria-label":o.titles[x]},x))})]},o.id)}),r.length>0&&a.jsxs("div",{className:"row times","aria-hidden":"true",children:[a.jsx("div",{className:"head"}),a.jsxs("div",{className:"ends",children:[a.jsx("span",{children:r[0]}),r.length>2&&a.jsx("span",{children:r[Math.floor(r.length/2)]}),r.length>1&&a.jsx("span",{children:r[r.length-1]})]})]}),a.jsx(oe,{tip:m})]})}const S=new WeakMap;function $(e){let s=S.get(e);return s===void 0&&S.set(e,s=Date.parse(e.ts)),s}const M=["error","warn","info","debug","trace"];function pe(e,s,r,n=24){const t=r?M.indexOf(r):M.length-1,m=M.filter((g,f)=>s.includes(g)&&f<=t),l=e.map($).filter(Number.isFinite);if(!l.length)return{rows:m.map(g=>({level:g,counts:[]})),buckets:[],width:0,busiest:null};const p=Math.min(...l),o=Math.max(...l),c=ne(p,o,n),v=c.length>1?c[1]-c[0]:Math.max(o-p,6e4),x=new Map(m.map(g=>[g,new Array(c.length).fill(0)])),u=new Array(c.length).fill(0),j=new Array(c.length).fill(0);for(const g of e){const f=$(g),y=x.get(g.level);if(!y||!Number.isFinite(f))continue;const w=Math.min(c.length-1,Math.floor((f-c[0])/v));y[w]++,u[w]++,g.level==="error"&&j[w]++}const i=g=>g.reduce((f,y,w)=>y>g[f]?w:f,0),h=j.reduce((g,f)=>g+f,0),d=i(h?j:u);return{rows:m.map(g=>({level:g,counts:x.get(g)})),buckets:c,width:v,busiest:{start:c[d],count:h?j[d]:u[d],errors:h}}}function me({records:e,offered:s,minimum:r,setMinimum:n}){const t=L(),m=O[R()],l=P(),p=b.useMemo(()=>pe(e,s,r),[e,s,r]),o=b.useMemo(()=>new Intl.DateTimeFormat(m,{hour:"2-digit",minute:"2-digit",hourCycle:"h23"}),[m]),c=b.useCallback(i=>`${o.format(i)}–${o.format(i+p.width)}`,[o,p.width]),v=b.useMemo(()=>{const i=Object.keys(T).map(h=>{const d=t(T[h]);return[h,{text:d,label:a.jsxs(W,{quiet:!0,small:!0,className:h===r?"current":void 0,label:t(h===r?"log.chart.current":"log.chart.minimum",{level:d}),onPress:()=>n(h),children:[h===r&&a.jsx(q,{}),d]})}]});return new Map(i)},[r,n,t]),x=b.useMemo(()=>{const i={error:l.negative,warn:l.notice,info:l.info,debug:l.subtle,trace:l.muted},h=p.buckets.map(c);return{columns:p.buckets.map(d=>o.format(d)),rows:p.rows.map(d=>{const{text:g,label:f}=v.get(d.level);return{id:d.level,color:i[d.level],label:f,counts:d.counts,titles:d.counts.map((y,w)=>t("log.chart.cell",{time:h[w],level:g,n:y}))}})}},[p,c,o,v,l,t]);if(!e.length)return null;const u=p.busiest,j=u?u.errors?[{label:t("log.chart.errors"),value:t("log.chart.count",{n:u.errors}),icon:a.jsx(k,{}),tone:"negative"},{label:t("log.chart.peakErrors"),icon:a.jsx(C,{}),tint:"c1",value:c(u.start),caption:t("log.chart.count",{n:u.count})}]:[{label:t("log.chart.errors"),value:t("log.chart.count",{n:0}),icon:a.jsx(k,{}),tint:"c5"},{label:t("log.chart.peak"),icon:a.jsx(C,{}),tint:"c1",value:c(u.start),caption:t("log.chart.count",{n:u.count})}]:[];return a.jsxs("div",{className:"rp-chart-page",children:[a.jsx(se,{facts:j}),a.jsx(H,{title:t("log.chart.title"),note:t("log.chart.sample",{n:e.length}),children:a.jsx(de,{label:t("log.chart.title"),columns:x.columns,rows:x.rows})})]})}const D=["trace","debug","info","warn","error"],he={trace:"muted",debug:"neutral",info:"info",warn:"warn",error:"err"},A=new WeakMap;function fe(e,s,r){const n=A.get(e);if(n&&n.locale===s)return n.row;const t={id:e.id,timestamp:I(e.ts,s),iso:e.ts,levelText:N(T,e.level,r),tone:he[e.level],target:e.target,gap:!1,message:e.message+(e.fields?" "+Object.entries(e.fields).map(([m,l])=>`${m}=${typeof l=="string"?l:JSON.stringify(l)}`).join(" "):"")};return A.set(e,{locale:s,row:t}),t}function xe(e,s,r,n,t,m=new Set,l){const p=o=>!!l&&D.indexOf(o){const c=fe(o,n,t);return m.has(o)?[{...c,id:`gap ${o.id}`,timestamp:"",iso:"",levelText:"",target:"",gap:!0,message:t("log.gap")},c]:[c]}),levels:s.map(o=>({id:o,label:p(o)?t("log.levelNotRecorded",{level:N(T,o,t)}):N(T,o,t)})),recordedText:l?t("log.recorded",{level:N(T,l,t)}):null,exportBase:`${r||"engine"}-log`}}function be(e,s,r){return r(ue(e,s,{forbidden:"log.emptyForbidden",off:"log.emptyNotRecorded",filtered:"log.emptyFiltered",empty:"log.empty"}))}function ve(e,s,r,n,t,m,l){return s?{tone:"err",text:l("log.disconnected")}:r?{tone:"neutral",text:l("log.paused",{n:n>t?`${G(t,m)}+`:n})}:{tone:e?"ok":"warn",text:l(e?"log.connected":"log.reconnecting")}}function je(e,s=[]){return s.includes(e)?e:s.includes("info")?"info":s[0]}function we(e,s,r){return[...e].reverse().flatMap(n=>{const t=`${n.ts} ${n.level.toUpperCase().padEnd(5)} ${n.target} ${n.message}${n.fields?" "+JSON.stringify(n.fields):""}`;return s.has(n)?[t,r("log.gap")]:[t]}).join(`
+`)+`
+`}const ye=[];function Te(){const e=L(),s=O[R()],r=J(),n=_(),[t,m]=b.useState("info"),l=b.useCallback(f=>m(f),[]),[p,o]=b.useState(""),[c,v]=b.useState(!1),x=V(p.trim()),u=r.data?.resources.logs,j=je(t,u?.levels),i=K({level:j,target:x,paused:c}),h=Q(r.data?.resources.runtime_settings.available??!1).data,d=h?.log.level,g=b.useMemo(()=>xe(i.records,u?.levels??[],n.data?.engine.name,s,e,i.gaps,d),[i.records,i.gaps,u,n.data,s,e,d]);return{...g,empty:be(h?.recording?.logs,!!x,e),status:ve(i.connected,!!i.error,c,i.pending,U,s,e),records:i.records,offered:u?.levels??ye,level:j??"",setLevel:l,target:p,setTarget:o,paused:c,setPaused:v,error:r.error??i.error,loading:!r.error&&!i.error&&!i.connected&&!i.records.length,clear:i.clear,retry:r.error?r.refetch:i.retry,export:()=>ce(ge(g.exportBase,"txt"),we(i.records,i.gaps,e),"text/plain;charset=utf-8")}}function Oe(){const e=L(),s=Te(),r=b.useMemo(()=>[{id:"ts",label:e("ui.time"),minWidth:200,grow:0,drop:2,render:t=>!t.gap&&a.jsx(F,{className:"rp-code",text:t.iso,children:t.timestamp})},{id:"level",label:e("log.level"),minWidth:90,grow:0,drop:3,render:t=>!t.gap&&a.jsx(E,{small:!0,tone:t.tone,children:t.levelText})},{id:"target",label:e("log.target"),minWidth:160,grow:0,drop:1,render:t=>a.jsx("span",{className:"rp-code",children:t.target})},{id:"message",label:e("log.message"),minWidth:280,grow:3,isRowHeader:!0,render:t=>a.jsx(F,{children:t.message})}],[e]),n=b.useCallback(t=>a.jsx(z,{inline:!0,items:t.gap?[[e("log.message"),t.message]]:[[e("ui.time"),t.timestamp],[e("log.level"),t.levelText],[e("log.target"),t.target],[e("log.message"),t.message]]}),[e]);return a.jsxs("div",{className:"rp-page",children:[a.jsxs("div",{className:"rp-toolbar",children:[a.jsx(X,{side:!0,label:e("log.level"),value:s.level,onChange:s.setLevel,items:s.levels}),a.jsx(Y,{search:!0,label:e("log.target"),value:s.target,width:240,placeholder:e("log.targetPlaceholder"),onChange:s.setTarget}),a.jsx(Z,{isSelected:s.paused,onChange:s.setPaused,children:e("log.pause")}),a.jsx(E,{small:!0,tone:s.status.tone,children:s.status.text}),s.recordedText&&a.jsx("span",{className:"rp-label",children:s.recordedText}),a.jsx("span",{className:"rp-grow"}),a.jsx(ie,{actions:[{id:"clear",label:e("log.clear"),isDisabled:!s.rows.length,onAction:s.clear},{id:"export",label:e("log.export"),icon:a.jsx(ee,{}),isDisabled:!s.rows.length,onAction:s.export}]})]}),a.jsx(te,{error:s.error,onRetry:s.retry}),a.jsx(me,{records:s.records,offered:s.offered,minimum:s.level,setMinimum:s.setLevel}),a.jsx(le,{label:e("nav.logs"),stream:!0,rows:s.rows,height:640,loading:s.loading,empty:s.empty,cols:r,detail:n})]})}export{Oe as Logs};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-BdGpTyio.js b/luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-Dmxd0d8_.js
similarity index 52%
rename from luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-BdGpTyio.js
rename to luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-Dmxd0d8_.js
index 2b9c26bd2..a15a2957f 100644
--- a/luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-BdGpTyio.js
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/NodeSearch-Dmxd0d8_.js
@@ -1 +1 @@
-import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as s,a6 as a,T as c}from"./index-zQjLFfuj.js";import{d as i}from"./Virtualizer-CTh266-x.js";import{$ as b}from"./useFilter-BYneYrGs.js";import{$ as f}from"./ListLayout-DU_9AgrU.js";function x({children:t}){const o=s(),{contains:r}=b({sensitivity:"base"});return e.jsxs(a,{filter:r,children:[e.jsx(c,{search:!0,label:o("policy.filter"),autoFocus:!0,className:"rp-menu-search"}),e.jsx(i,{layout:f,layoutOptions:{rowHeight:32,headingHeight:26},children:t})]})}export{x as NodeSearch};
+import{j as e}from"./vendor-react-Bf71BWbF.js";import{u as s,ad as a,T as c}from"./index-CXHBmSa5.js";import{d as i}from"./Virtualizer--Vfl8O3n.js";import{$ as b}from"./useFilter-DZ8TXqn_.js";import{$ as f}from"./ListLayout-CPapuywx.js";function x({children:t}){const o=s(),{contains:r}=b({sensitivity:"base"});return e.jsxs(a,{filter:r,children:[e.jsx(c,{search:!0,label:o("policy.filter"),autoFocus:!0,className:"rp-menu-search"}),e.jsx(i,{layout:f,layoutOptions:{rowHeight:32,headingHeight:26},children:t})]})}export{x as NodeSearch};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-BPHOu_UD.js b/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-BPHOu_UD.js
deleted file mode 100644
index 3d99bd10f..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-BPHOu_UD.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import{r as j,j as t}from"./vendor-react-Bf71BWbF.js";import{u as q,aB as ze,B as A,cm as ve,aE as H,$ as _e,a2 as Se,a1 as Z,a3 as Xe,_ as le,as as Je,E as Te,b as Ke,a8 as Qe,aI as O,bj as Ce,bk as Ye,bm as Ze,ax as en,cg as Le,aS as nn,U as De,av as ee,ay as sn,b9 as $e,at as an,bo as tn,a7 as Re,T as z,aT as me,j as Ge,F as on,k as ne,J as rn,H as ye,o as ln,cR as Ae,cS as dn,aj as cn,aN as un,ae as mn,V as Ne,ah as pn,ag as ce,W as se,aU as bn,ch as vn,X as he,b0 as C,cp as pe,cD as fe,a as ge,cC as hn,b2 as fn,z as We,cT as gn,cw as xn,cU as we,co as jn,a4 as kn,cV as yn,cW as Nn,cn as wn,cX as Pn,cY as Mn,b4 as _n,b5 as Sn,cZ as Tn,cq as Cn,bc as Ln,M as Dn,I as $n,cl as Rn,cK as Gn}from"./index-zQjLFfuj.js";import{F as An}from"./FactStrip-vcLr7nBw.js";import{u as Wn,C as Fn,p as Bn}from"./layout-B3T-zLsm.js";import{D as Fe,c as En}from"./Table-DLlwyNFJ.js";import{T as In}from"./TimeCell-DxlzlVpw.js";import{A as On}from"./AddCircle-DSsJ-CRu.js";import{u as Hn}from"./outbounds-CM0Hhk3q.js";import{p as qn,b as Un}from"./policyText-IIH31itq.js";import{$ as Vn}from"./useFilter-BYneYrGs.js";import{p as zn}from"./probe-CjOLdDVD.js";import{a as Xn}from"./setup-BqwQo7FE.js";import{P as Jn}from"./PolicyPicker-iyQz7WhP.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";function Pe({kind:e,color:s}){return t.jsx("i",{className:"rp-marker "+e,style:s?{color:s}:void 0,"aria-hidden":"true"})}function Kn({label:e,groups:s,legend:n,max:a,fmt:d,limit:o=10,showAll:c}){const r=q(),u=ze(),{ref:i,tip:p,show:m,hide:h}=Wn(),[y,b]=j.useState(new Set),l=[0,a/4,a/2,3*a/4,a],v=x=>Math.min(100,x/a*100);return t.jsxs("div",{className:"rp-markerplot rp-chart-hover",ref:i,onPointerLeave:h,role:"group","aria-label":e,"aria-describedby":u,children:[t.jsx("ul",{className:"legend",children:n.map(x=>t.jsxs("li",{children:[t.jsx(Pe,{kind:x.kind}),x.label]},x.kind))}),t.jsxs("div",{className:"axis","aria-hidden":"true",children:[t.jsx("span",{}),t.jsx("div",{className:"scale",children:l.map(x=>t.jsx("span",{style:{insetInlineStart:`${v(x)}%`},children:d(x)},x))}),t.jsx("span",{})]}),s.map(x=>t.jsxs("section",{"aria-label":x.label,children:[s.length>1&&t.jsx("h4",{className:"rp-label",children:x.label}),(y.has(x.id)?x.rows:x.rows.slice(0,o)).map(f=>{const S=Object.values(f.values).filter(P=>P!==void 0),_=v(Math.min(...S)),R=v(Math.max(...S));return t.jsxs("div",{className:"row",onPointerMove:P=>m(P,[f.label,...f.details]),children:[t.jsx("span",{className:"name",children:f.label}),t.jsxs("div",{className:"track",role:"img","aria-label":f.label+r("ui.separator")+f.description,children:[l.map(P=>t.jsx("i",{className:"grid",style:{insetInlineStart:`${v(P)}%`}},P)),R>_&&t.jsx("i",{className:"span",style:{insetInlineStart:`${_}%`,width:`${R-_}%`}}),["tick","diamond","dot"].map(P=>f.values[P]===void 0?null:t.jsx("span",{className:"at "+P+(f.values[P]>a?" over":""),style:{insetInlineStart:`${v(f.values[P])}%`},children:t.jsx(Pe,{kind:P,color:P==="dot"?f.tone:void 0})},P))]}),t.jsx("span",{className:"value",children:f.text})]},f.id)}),!y.has(x.id)&&x.rows.length>o&&t.jsx("div",{className:"row more",children:t.jsx(A,{quiet:!0,small:!0,onPress:()=>b(f=>new Set([...f,x.id])),children:c(x.rows.length)})}),x.notes.map(f=>t.jsx("p",{className:"rp-note note",children:f},f))]},x.id)),t.jsx(Fn,{tip:p})]})}function Qn(e,s,n){const a=new Map((s??[]).map(r=>[r.id,r.name])),d=new Map,o=(r,u)=>{let i=d.get(r);return i||d.set(r,i={id:r,label:u,rows:[],missing:[]}),i};for(const r of e){const u=ve(r),i=n==="protocol"?[["protocol:"+(r.protocol??""),r.protocol??null]]:r.group_ids.length?r.group_ids.map(p=>["group:"+p,a.get(p)??p]):[["group:",null]];for(const[p,m]of i){const h=o(p,m);u?.state==="healthy"&&u.latency_ms!==null?h.rows.push({id:r.id,name:r.name,latest:u.latency_ms,moving:u.moving_avg_ms,avg10:u.avg10_ms}):h.missing.push({id:r.id,name:r.name,state:u?.state==="unavailable"?"unavailable":"unmeasured"})}}const c=[...d.values()];for(const r of c)r.rows.sort((u,i)=>u.latest-i.latest||H(u.name,i.name)),r.missing.sort((u,i)=>H(u.name,i.name));return c.sort((r,u)=>(r.label===null?1:0)-(u.label===null?1:0)||H(r.label??"",u.label??""))}function Yn(e){const s=e.flatMap(n=>n.rows);return{moving:s.some(n=>n.moving!==null),avg10:s.some(n=>n.avg10!==null)}}function Zn(e){const s=e.flatMap(d=>d.rows.flatMap(o=>[o.latest,o.moving??o.latest])).sort((d,o)=>d-o),n=Math.max(10,(Bn(s,90)??0)*1.25),a=n<=100?20:n<=500?100:n<=2e3?500:1e3;return Math.ceil(n/a)*a}function es(){const e=_e().data?.resources,s=Se(Z(e,"nodes",{whileLoading:!0})),n=Xe(Z(e,"groups",{whileLoading:!1})),[a,d]=j.useState("group"),o=j.useMemo(()=>Qn(s.data??[],n.data,a),[s.data,n.data,a]);return{nodes:s,by:a,setBy:d,view:o}}const ue=6;function ns(){const e=q(),s=le(),n=Je(),{nodes:a,by:d,setBy:o,view:c}=es();if(a.error&&!a.data)return t.jsx(Te,{error:a.error,onRetry:a.refetch});if(!a.data)return t.jsx(Ke,{});if(!a.data.length)return t.jsx(Qe,{children:e("ui.empty")});const r={ok:n.positive,warn:n.notice,err:n.negative},u=Yn(c),i=[...new Map(c.flatMap(b=>b.rows).map(b=>[b.id,b])).values()].sort((b,l)=>b.latest-l.latest),p=new Set(c.flatMap(b=>b.missing.filter(l=>l.state==="unavailable").map(l=>l.id))).size,m=i.length?[{label:e("nodes.latency.lowest"),icon:t.jsx(Ce,{}),tint:"c2",value:i[0].name,caption:O(i[0].latest,e)},{label:e("nodes.latency.highest"),icon:t.jsx(Ye,{}),tint:"c4",value:i[i.length-1].name,caption:O(i[i.length-1].latest,e)},{label:e("nodes.latency.unavailable"),value:e("nodes.latency.count",{n:p}),icon:t.jsx(Ze,{}),tint:"c5",tone:p?"negative":void 0}]:[],h=b=>{const l=De(s,b.slice(0,ue).map(v=>v.name));return b.length>ue?`${l} ${e("nodes.latency.andMore",{n:b.length-ue})}`:l},y=b=>{const l=b.filter(x=>x.state==="unavailable"),v=b.filter(x=>x.state==="unmeasured");return[...l.length?[e("nodes.latency.unavailableList",{n:l.length,names:h(l)})]:[],...v.length?[e("nodes.latency.unmeasuredList",{n:v.length,names:h(v)})]:[]]};return t.jsxs("div",{className:"rp-chart-page",children:[t.jsx(An,{facts:m}),t.jsx(en,{title:e("nodes.latency.title"),note:e("nodes.latency.sample",{n:a.data.length}),aside:t.jsx(nn,{label:e("nodes.latency.by"),value:d,onChange:b=>o(b),items:[["group",e("nodes.latency.byGroup")],["protocol",e("nodes.latency.byProtocol")]]}),children:t.jsx(Kn,{label:e("nodes.latency.title"),max:Zn(c),fmt:b=>O(b,e),showAll:b=>e("nodes.latency.showAll",{n:b}),legend:[{kind:"dot",label:e("nodes.latency.latest")},...u.moving?[{kind:"diamond",label:e("nodes.latency.moving")}]:[],...u.avg10?[{kind:"tick",label:e("nodes.latency.avg10")}]:[]],groups:c.map(b=>({id:b.id,label:b.label??e(d==="group"?"nodes.latency.noGroup":"nodes.latency.noProtocol"),rows:b.rows.map(l=>{const v=[e("ui.valuePair",{label:e("nodes.latency.latest"),value:O(l.latest,e)}),...u.moving?[e("ui.valuePair",{label:e("nodes.latency.moving"),value:O(l.moving,e)})]:[],...u.avg10?[e("ui.valuePair",{label:e("nodes.latency.avg10"),value:O(l.avg10,e)})]:[]];return{id:l.id,label:l.name,values:{dot:l.latest,diamond:l.moving??void 0,tick:l.avg10??void 0},text:O(l.latest,e),tone:r[Le(l.latest)],description:v.join(e("ui.separator")),details:v}}),notes:y(b.missing)}))})})]})}function ss({model:e}){const s=q();return t.jsxs(t.Fragment,{children:[e.canManage&&t.jsxs("div",{className:"rp-toolbar",children:[t.jsx("span",{className:"rp-grow"}),t.jsx(A,{small:!0,onPress:e.onAdd,children:s("nodes.addProvider")})]}),t.jsx(Fe,{label:s("nodes.providers"),loading:e.loading,rows:e.rows,height:280,fit:!0,selected:e.selected,onSelect:e.onSelect,selectOnFocus:!0,empty:s("nodes.noProviders"),cols:[{id:"name",label:s("nodes.provider"),minWidth:140,grow:2,isRowHeader:!0,render:n=>t.jsx("span",{className:"rp-chain",children:t.jsx(ee,{text:n.url,children:n.name})})},{id:"kind",label:s("nodes.kindLabel"),minWidth:150,grow:0,drop:5,render:n=>t.jsx(sn,{children:n.kind})},{id:"count",label:s("nodes.count"),minWidth:80,grow:0,align:"end",drop:6,render:n=>n.count},{id:"usage",label:s("nodes.usage"),minWidth:200,drop:2,render:n=>n.usage},{id:"updated",label:s("nodes.updated"),minWidth:140,drop:3,render:n=>t.jsx(In,{at:n.updatedAt})},{id:"interval",label:s("nodes.interval"),minWidth:130,grow:0,drop:4,render:n=>n.hasInterval&&e.writable?t.jsx(ee,{text:e.sourceTip,children:t.jsx($e,{quiet:!0,label:n.intervalLabel,value:n.intervalValue,isDisabled:e.sourceBusy,onChange:n.setInterval,items:n.intervals,children:n.interval})}):n.interval},{id:"expires",label:s("nodes.expires"),minWidth:140,drop:1,render:n=>n.expires},{id:"status",label:s("ui.state"),minWidth:96,grow:0,drop:7,render:n=>n.status?t.jsx(an,{small:!0,tone:n.tone,children:t.jsx(ee,{text:n.error,children:n.status})}):"—"},{id:"actions",label:s("ui.actions"),minWidth:e.canManage?112:88,grow:0,render:n=>t.jsxs("span",{className:"rp-chain",children:[n.refreshable&&t.jsx(A,{small:!0,quiet:!0,icon:!0,isPending:n.refreshing,isDisabled:n.refreshDisabled,label:n.refreshLabel,onPress:n.refresh,children:t.jsx(tn,{className:"rp-spin-on-press"})}),n.removable&&t.jsx(A,{small:!0,quiet:!0,icon:!0,isDisabled:e.busy,label:n.removeLabel,onPress:n.remove,children:t.jsx(Re,{})})]})}]})]})}const Be=j.createContext(null);function as({row:e}){const s=j.useContext(Be);return t.jsx(A,{small:!0,quiet:!0,icon:!0,isPending:s===e.id,isDisabled:!!s,label:e.probeLabel,onPress:e.probe,children:t.jsx(Ce,{})})}function ts({model:e}){const s=q(),{canManage:n,writable:a,sourceBusy:d,busy:o}=e,c=j.useMemo(()=>[{id:"name",label:s("nodes.node"),minWidth:150,grow:2,isRowHeader:!0,sortable:!0,render:r=>t.jsx("span",{className:"rp-chain",children:t.jsx(ee,{children:r.name})})},{id:"protocol",label:s("nodes.protocol"),minWidth:144,grow:0,drop:2,sortable:!0,render:r=>r.protocol},{id:"latency",label:s("nodes.latency"),minWidth:96,grow:0,align:"end",sortable:!0,render:r=>t.jsx("span",{className:r.latencyClass,children:r.latency})},{id:"groups",label:s("nodes.groups"),minWidth:200,drop:1,render:r=>t.jsx(ee,{children:r.groups})},{id:"actions",label:s("ui.actions"),minWidth:n?108:72,grow:0,render:r=>t.jsxs("span",{className:"rp-chain",children:[r.canProbe&&t.jsx(as,{row:r}),a&&t.jsx($e,{quiet:!0,chevron:!1,label:r.joinLabel,isDisabled:d,items:r.menu,onAction:r.join,children:t.jsx(On,{})}),r.removable&&t.jsx(A,{small:!0,quiet:!0,icon:!0,isDisabled:o,label:r.removeLabel,onPress:r.remove,children:t.jsx(Re,{})})]})}],[s,n,a,d,o]);return t.jsxs(t.Fragment,{children:[e.writable&&e.sourceTip&&t.jsx("p",{className:"rp-note",children:e.sourceTip}),t.jsxs("div",{className:"rp-toolbar",children:[t.jsx(z,{label:s("nodes.search"),search:!0,value:e.search,width:240,onChange:e.setSearch}),t.jsx(me,{label:s("nodes.group"),side:!0,value:e.group,onChange:e.setGroup,items:e.groups}),t.jsx(me,{label:s("nodes.protocol"),side:!0,value:e.protocol,onChange:e.setProtocol,items:e.protocols}),t.jsx("span",{className:"rp-label",children:e.shown}),t.jsx("span",{className:"rp-grow"}),e.canManage&&t.jsx(A,{small:!0,onPress:e.onAdd,children:s("nodes.addNode")})]}),t.jsx(Be.Provider,{value:e.probeBusy,children:t.jsx(Fe,{label:e.label,loading:e.loading,rows:e.rows,height:520,empty:s("nodes.empty"),sort:e.sort,onSort:e.setSort,cols:c})})]})}function os(e){const s=/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(e.trim());if(!s)return null;const n={ms:1/1e3,s:1,m:60,h:3600};return Math.ceil(Number(s[1])*(n[s[2]??"s"]??1))}function re(e){if(!e)return null;try{return new URL(e).hostname||null}catch{return null}}function rs(e){const s=ln(e).trim(),{tokens:n}=Ge(s),a=n[0];if(!a)return null;const d=s.slice(a.from,a.to),o=n[1],c=o&&s.slice(o.from,o.to)===":"&&!s.slice(o.to).startsWith("//"),r=c?o.to:0,u=n.find(b=>b.from>=r);if(!u)return null;const i=u.kind==="quoted";let p=i?ne(s.slice(u.from,u.to)):s.slice(r).trim(),m=c?ne(d):null;if(!m){const b=p.indexOf(":");b!==-1&&!p.startsWith("://",b)?(m=p.slice(0,b).trim(),p=p.slice(b+1)):m=re(p)}const h=i?s.slice(u.to).trim():"",y=h.startsWith("(")&&h.endsWith(")")?ne(h.slice(1,-1)):null;return h&&y===null?null:m?{tag:m,url:p,ua:y}:null}function Ee(e){const{blocks:s,tokens:n}=Ge(e),a=[];for(const d of s.filter(o=>o.name==="subscription"))for(let o=0;o=d.close||c.depth!==d.depth+1||c.kind==="comment")continue;const r=e.lastIndexOf(`
-`,c.from-1)+1,u=/^[ \t]*$/.test(e.slice(r,c.from))?r:c.from,i=d.children.find(l=>l.from===c.from);if(i){for(;n[o+1]?.fromf.name==="url"),x=l.find(f=>f.name==="interval");a.push({from:u,to:i.to,block:i,tag:i.name,host:v?re(ne(v.value)):null,interval:x?os(ne(x.value)):null,fields:l,parts:null});continue}const p=n[o+1];p&&e.slice(p.from,p.to)===":"&&!e.slice(p.to).startsWith("//")&&(o+=2);const m=n[o];if(!m||m.from>=d.close)break;if(m.kind!=="quoted")for(;n[o+1]?.from===n[o].to&&!/[(){}]/.test(e.slice(n[o+1].from,n[o+1].to));)o++;if(e[n[o+1]?.from]==="(")for(o++;n[o+1]&&!(e[n[o].from]===")"&&n[o].parens===1);)o++;let h=n[o].to,y;n[o+1]?.kind==="comment"&&n[o+1].line===n[o].line&&(y=e.slice(n[o+1].from,n[o+1].to),h=n[++o].to);const b=rs(e.slice(u,h));b&&a.push({from:u,to:h,tag:b.tag,host:re(b.url),interval:null,fields:[],parts:b,comment:y})}return a}function ls(e){return Ee(e).map(({tag:s,host:n,interval:a})=>({tag:s,host:n,interval:a}))}function is(e,s,n){const a=Ee(e).find(u=>u.tag===s);if(!a||a.interval===n)return e;const d=e.slice(a.from,a.to).match(/^[ \t]*/)?.[0]??" ",o=d+(d.includes(" ")?" ":" ");if(a.parts){const u=[`${d}${rn(s)}: {`,`${o}url: ${ye(a.parts.url)}`];return a.parts.ua!==null&&u.push(`${o}ua: ${ye(a.parts.ua)}`),u.push(`${o}interval: '${n}s'`,`${d}}${a.comment?" "+a.comment:""}`),e.slice(0,a.from)+u.join(`
-`)+e.slice(a.to)}const c=a.fields.find(u=>u.name==="interval");if(c)return e.slice(0,c.valueFrom)+` '${n}s'`+e.slice(c.valueTo);if(!a.block)return e;const r=e.lastIndexOf(`
-`,a.block.close-1)+1;return e.slice(0,r)+`${o}interval: '${n}s'
-`+e.slice(r)}function ds(e,s,n,a){const d=ve(e),o=d?.state==="healthy"&&d.latency_ms!=null;return{id:e.id,name:e.name,protocol:e.protocol??"—",latency:o?O(d.latency_ms,a):d?.state==="unavailable"?a("ui.unavailable"):"—",latencyClass:o?`ms ${Le(d.latency_ms)}`:d?.state==="unavailable"?"ms err":"ms",groups:e.group_ids.length?De(n,e.group_ids.map(c=>s.get(c)??c)):"—",probeLabel:a("nodes.probe",{name:e.name}),joinLabel:a("nodes.joinGroup",{name:e.name}),removeLabel:a("nodes.remove",{name:e.name})}}const cs=e=>bn(ve(e));function us(e,s,n,a){const d=new Map;for(const l of s){if(!l.provider_id||!l.subscription_tag)continue;const v=d.get(l.provider_id)??new Set;v.add(l.subscription_tag),d.set(l.provider_id,v)}const o=l=>{const v=d.get(l);return v?.size===1?[...v][0]:void 0},c=l=>{const v=re(l.url_redacted),x=v?n.filter(f=>f.host===v):[];return x.length===1?x[0].tag:void 0},r=new Map,u=e.filter(l=>l.kind==="subscription");for(const l of u){const v=o(l.id)??c(l);v&&r.set(l.id,v)}const i=u.filter(l=>!r.has(l.id)),p=new Set(r.values()),m=n.filter(l=>!p.has(l.tag));i.length===1&&m.length===1&&r.set(i[0].id,m[0].tag);const h=e.map(l=>{const v=o(l.id);return{...l,displayName:r.get(l.id)??l.name,configTag:l.kind==="subscription"&&v&&n.filter(x=>x.tag===v).length===1?v:void 0}}),y={builtin:0,unattributed:0};for(const l of s)l.provider_id==null&&y[Ae(l)]++;const b=[];for(const l of["builtin","unattributed"]){const v=y[l];v&&b.push({id:dn(l,e),name:a(l==="builtin"?"nodes.kind.builtin":"nodes.kind.unattributed"),kind:l,url_redacted:null,node_count:v,updated_at:null,expires_at:null,traffic:null,status:"ok",last_error:null})}return{list:[...b,...h]}}function ms(e,s){return s!==null&&e.some(n=>n.id===s)?s:(e.find(n=>n.kind!=="builtin"&&n.kind!=="unattributed")??e[0])?.id??null}function ps(e,s,n){return e.filter(a=>s===void 0||(s===null?a.provider_id==null&&Ae(a)==="builtin"==(n==="builtin"):a.provider_id===s))}function bs(e,s,n,a,d,o){const c=s.trim(),r=e.filter(m=>(!c||o(m.name,c))&&(!n||m.group_ids.includes(n))&&(!a||m.protocol===a)),u=d.direction==="ascending"?1:-1,i=d.column==="latency"?new Map(r.map(m=>[m.id,cs(m)])):new Map,p={name:(m,h)=>H(m.name,h.name),protocol:(m,h)=>H(m.protocol??"",h.protocol??""),latency:(m,h)=>vn(i.get(m.id),i.get(h.id))||H(m.name,h.name)};return r.sort((m,h)=>u*(p[d.column]??p.name)(m,h))}const be=[3600,21600,43200,86400];function xe(e,s,n){return e===0?n("nodes.manualOnly"):be.includes(e)?n("nodes.everyHours",{n:e/3600}):cn(String(e),s)}function Ie(e,s,n){return[0,...be,...e===null||e===0||be.includes(e)?[]:[e]].map(a=>({id:String(a),label:xe(a,s,n)}))}function vs(e,s){const n={name:e.name.trim(),kind:"subscription",url:e.value.trim()},a=Number(e.interval);s?.update_interval!==void 0&&e.interval&&a!==s.update_interval&&(n.update_interval=a);const d=e.agent.trim();return s?.user_agent!==void 0&&d&&d!==s.user_agent&&(n.user_agent=d),s?.cache!==void 0&&e.cache!==null&&e.cache!==s.cache&&(n.cache=e.cache),n}function hs(e,s,n,a){const d={subscription:"nodes.kind.subscription",file:"nodes.kind.file",inline:"nodes.kind.inline",builtin:"nodes.kind.builtin",unattributed:"nodes.kind.unattributed"},o={ok:"nodes.status.ok",stale:"nodes.status.stale",error:"nodes.status.error"},c={ok:"ok",stale:"warn",error:"err"},r=e.kind==="builtin"||e.kind==="unattributed",u=e.traffic?un(e.traffic.upload_bytes,e.traffic.download_bytes):null,i=e.kind==="subscription"?s:void 0,p=e.displayName??e.name;return{id:e.id,name:p,url:e.url_redacted??void 0,kind:Ne(d,e.kind,a),count:se(e.node_count,n),usage:u===null?"—":e.traffic?.total_bytes?a("ui.fraction",{part:ce(u,n),whole:ce(e.traffic.total_bytes,n)}):ce(u,n),updatedAt:r?null:e.updated_at,expires:e.expires_at?pn(e.expires_at,n):"—",interval:i==null?"—":xe(i,n,a),intervalValue:i==null?"":String(i),hasInterval:i!==void 0,intervalLabel:a("nodes.intervalOf",{name:p}),intervals:i===void 0?[]:Ie(i,n,a),status:r?null:Ne(o,e.status,a),tone:c[e.status],error:e.last_error?mn(e.last_error.code,e.last_error.message,a):void 0,refreshLabel:a("nodes.refresh",{name:p}),removeLabel:a("nodes.remove",{name:p})}}function fs(e){const s=q(),n=he[le()],{refresh:a}=e,d=new Map(e.entries.map(c=>[c.tag,c.interval]));return{rows:e.rows.map(c=>({...hs(c,c.configTag?d.get(c.configTag):void 0,n,s),refreshable:c.kind==="subscription"&&e.canRefresh,refreshing:a.busy===c.id,refreshDisabled:!!a.busy,refresh:()=>void a.refresh(c.id).then(r=>{r&&("degraded"in r?C("info",s("nodes.refreshedDegraded",{name:c.name})):C("positive",s("nodes.refreshed",{name:c.name,n:se(r.node_count,n)})))},r=>fe(r,s,s("nodes.refreshFailed",{name:c.name}))),removable:e.canManage&&(c.kind==="subscription"||c.kind==="file"),remove:()=>{(c.kind==="subscription"||c.kind==="file")&&e.onRemove(c)},setInterval:r=>{if(!c.configTag)return;const u=Number(r);e.source.apply(i=>is(i,c.configTag,u)).then(i=>{i.kind==="ok"&&C("positive",s("nodes.intervalSet",{name:c.name,interval:xe(u,n,s)}));const p=pe(i,s);p&&C(p.kind,p.text,{detail:p.detail})})}})),loading:e.loading,selected:e.selected,onSelect:e.onSelect,canManage:e.canManage,busy:e.busy,writable:e.source.writable,sourceBusy:e.source.busy||!e.source.main,sourceTip:e.source.error?ge(e.source.error,s):void 0,onAdd:e.onAdd}}function gs(e){const{nodes:s,names:n,providers:a,source:d,query:o,reload:c,joinGroup:r,onNewGroup:u,onRemove:i,canManage:p}=e,m=q(),h=le(),y=he[h],b=hn(c),[l,v]=j.useState(o??"");fn(o,g=>v(g??""));const[x,f]=j.useState(""),[S,_]=j.useState(""),[R,P]=j.useState({column:"name",direction:"ascending"}),W=j.useMemo(()=>[...new Set(s.flatMap(g=>g.group_ids))].sort((g,w)=>H(n.get(g)??g,n.get(w)??w)).map(g=>({id:g,label:n.get(g)??g})),[s,n]),T=j.useMemo(()=>[...new Set(s.map(g=>g.protocol??""))].filter(Boolean).sort(H).map(g=>({id:g,label:g})),[s]),D=W.some(g=>g.id===x)?x:"",F=T.some(g=>g.id===S)?S:"",{contains:L}=Vn({sensitivity:"base"}),N=j.useMemo(()=>bs(s,l,D,F,R,L),[s,l,D,F,R,L]),ae=j.useMemo(()=>We(d.main?.content??"").map(g=>({...g,names:new Set(gn(g))})),[d.main?.content]),B=j.useMemo(()=>new Map(s.map(g=>[g.id,new Set(g.group_ids.map(w=>n.get(w)??w))])),[s,n]),K=j.useMemo(()=>new Set(a.filter(g=>g.kind==="inline").map(g=>g.id)),[a]),{probe:U,canProbe:X,busy:ie}=b,J=j.useCallback(g=>({...ds(g,n,h,m),canProbe:X&&!xn(g.protocol),probe:()=>void U(g.id).then(w=>{if(!w)return;const{kind:de,text:oe}=zn(w,g.id,g.name,m);C(de,oe)},w=>fe(w,m,m("nodes.probeError",{name:g.name}))),menu:()=>[...ae.filter(w=>!w.names.has(g.name)&&!B.get(g.id)?.has(w.name)).map(w=>({id:w.name,label:w.name,desc:qn(w.policy,m)})),{id:"/new",label:m("nodes.newGroup")}],join:w=>w==="/new"?u(g):r(g,w),removable:p&&typeof g.provider_id=="string"&&K.has(g.provider_id),remove:()=>i(g)}),[n,h,X,U,m,ae,B,u,r,p,K,i]),Q=j.useMemo(()=>({build:J,rows:new WeakMap}),[J]),te=j.useMemo(()=>En(Q.rows,N,Q.build),[Q,N]);return{rows:te,probeBusy:ie,search:l,setSearch:v,group:D,setGroup:f,protocol:F,setProtocol:_,sort:R,setSort:P,groups:[{id:"",label:m("nodes.anyGroup")},...W],protocols:[{id:"",label:m("nodes.anyProtocol")},...T],shown:m("ui.fraction",{part:se(te.length,y),whole:se(s.length,y)}),loading:e.loading,label:e.label,canManage:p,busy:e.busy,writable:d.writable,sourceBusy:d.busy||!d.main,sourceTip:d.error?ge(d.error,m):void 0,onAdd:e.onAdd}}const Me={name:"",value:"",interval:"",agent:"",cache:null};function xs({go:e,query:s}){const n=q(),[a,d]=j.useState(null),[o,c]=j.useState(Me),[r,u]=j.useState(we[0].id),i=j.useRef(0),p=j.useRef(null),[m,h]=j.useState(null),[y,b]=j.useState(null),l=jn(!!a&&!!(o.name||o.value),()=>{i.current++,d(null)}),v=j.useCallback(k=>{i.current++,c(Me),u(we[0].id),b(null),d(k)},[]),x=he[le()],f=_e().data?.resources,S=kn(Z(f,"providers",{whileLoading:!0})),_=Se(Z(f,"nodes",{whileLoading:!0})),R=Hn(),{refetch:P}=S,{refetch:W}=_,T=j.useCallback(()=>{P(),W()},[P,W]),D=yn(T),F=Nn(T),L=wn(),N=j.useMemo(()=>ls(L.main?.content??""),[L.main?.content]),ae=j.useMemo(()=>new Set(We(L.main?.content??"").map(k=>k.name)),[L.main?.content]),{list:B}=j.useMemo(()=>us(S.data?.providers??[],_.data??[],N,n),[S.data,_.data,N,n]),K=j.useMemo(()=>new URLSearchParams(s),[s]),U=ms(B,K.get("provider")),X=B.find(k=>k.id===U)??null,ie=j.useMemo(()=>{const k=B.find($=>$.id===U);return ps(_.data??[],k?.kind==="builtin"||k?.kind==="unattributed"?null:k?.id,k?.kind)},[_.data,B,U]),{apply:J}=L,Q=j.useCallback((k,$)=>{J(V=>Pn(V,$,[k.name])).then(V=>{V.kind==="ok"&&C("positive",n("nodes.joined",{name:k.name,group:$}));const M=pe(V,n);M&&C(M.kind,M.text,{detail:M.detail})})},[J,n]),te=j.useCallback(()=>v({kind:"node"}),[v]),g=j.useCallback(k=>v({kind:"group",item:k}),[v]),w=j.useCallback(k=>v({kind:"removeNode",item:k}),[v]),de=async k=>{if(!a||p.current)return;p.current=a,h(a);const $=i.current,V=M=>{i.current===$?b(G=>({id:(G?.id??0)+1,text:M})):C("negative",M)};try{if(a.kind==="provider"){const M=await D.addProvider(vs(o,E));if(!M)return;const G=o.name.trim();if(f?.providers.can_refresh){i.current===$&&(l.clear(),k());const Y=()=>void F.refresh(M.id).then(I=>{I&&("degraded"in I?C("info",n("nodes.refreshedDegraded",{name:G})):C("positive",n("nodes.addedRefreshed",{name:G,n:se(I.node_count,x)})))},I=>fe(I,n,n("nodes.addedRefreshFailed",{name:G}),{label:n("ui.retry"),onAction:Y,closeOnAction:!0}));Y();return}C("positive",n("nodes.added",{name:G}))}else if(a.kind==="node"){const M=await D.addNode({name:o.name.trim(),link:o.value.trim()});if(!M)return;C("positive",n("nodes.added",{name:M.name}))}else if(a.kind==="group"){const M=o.name.trim(),G=a.item.name,Y=await J(Ve=>Tn(Ve,[{kind:"createGroup",group:M,policy:r},{kind:"addNode",group:M,value:G}])),I=pe(Y,n);if(I&&V(Cn(I,n)),Y.kind!=="ok")return;C("positive",n("nodes.joined",{name:G,group:M}))}else if(a.kind==="removeProvider"){if(!await D.removeProvider(a.item.id))return;C("positive",n("nodes.removed",{name:a.item.name}))}else{if(!await D.removeNode(a.item.id))return;C("positive",n("nodes.removed",{name:a.item.name}))}i.current===$&&(l.clear(),k())}catch(M){V(ge(M,n))}finally{p.current=null,h(null)}},oe=a?.kind==="removeProvider"||a?.kind==="removeNode",Oe=a===null?"":a.kind==="provider"?n("nodes.addProvider"):a.kind==="node"?n("nodes.addNode"):a.kind==="group"?n("nodes.newGroup"):n(a.kind==="removeProvider"?"nodes.removeProviderTitle":"nodes.removeNodeTitle",{name:a.item.name}),je=a?.kind==="group"?Un(o.name.trim(),ae,n):null,E=f?.providers.create_options,ke=/^[\x20-\x7E]{0,256}$/.test(o.agent.trim())?null:n("nodes.agentInvalid"),He=a?.kind==="provider"?Mn(o.name.trim())&&Xn(o.value)&&!ke:a?.kind==="node"?o.name.trim()!==""&&/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(o.value.trim()):a?.kind==="group"?je===null:!0,qe=fs({rows:B,loading:S.loading&&!S.data,selected:U,onSelect:k=>{if(!k)return;const $=new URLSearchParams(s);$.set("provider",k),e("nodes",$.toString(),{replace:!0})},canManage:!!f?.providers.can_manage,canRefresh:!!f?.providers.can_refresh,busy:!!D.busy,source:L,entries:N,reload:T,refresh:F,onAdd:()=>v({kind:"provider"}),onRemove:k=>v({kind:"removeProvider",item:k})}),Ue=gs({nodes:ie,providers:S.data?.providers??[],names:R,loading:_.loading&&!_.data,label:X?n("nodes.of",{name:X.displayName??X.name}):n("nav.nodes"),query:K.get("q"),source:L,canManage:!!f?.nodes.can_manage,busy:!!D.busy,reload:W,joinGroup:Q,onAdd:te,onNewGroup:g,onRemove:w});return{measured:Z(f,"nodes",{whileLoading:!0}),tab:Sn(s,["list","latency"],"list"),setTab:k=>e("nodes",_n(s,k,"list")),providerTable:qe,nodeTable:Ue,error:S.error??_.error,reload:T,dialog:a,setDialog:k=>{i.current++,b(null),d(k)},problem:y,form:o,setForm:k=>{p.current!==a&&c(k)},removing:oe,dialogTitle:Oe,formValid:He,submit:de,pending:a!==null&&m===a,submitting:m!==null,submitLabel:oe?n("nodes.remove",{name:a.item.name}):a?.kind==="group"?n("nodes.join"):n("nodes.add"),groupHelp:a?.kind==="group"?n("nodes.newGroupHelp",{name:a.item.name}):"",groupNameError:o.name.trim()?je:null,agentError:ke,options:E&&{intervals:E.update_interval===void 0?null:Ie(E.update_interval,x,n),interval:o.interval||String(E.update_interval),agent:E.user_agent,cache:E.cache===void 0?null:o.cache??E.cache},policy:r,setPolicy:k=>{p.current!==a&&u(k)}}}function Ws(e){const s=q(),{measured:n,tab:a,setTab:d,providerTable:o,nodeTable:c,error:r,reload:u,dialog:i,setDialog:p,problem:m,form:h,setForm:y,removing:b,dialogTitle:l,formValid:v,submit:x,pending:f,submitting:S,submitLabel:_,groupHelp:R,groupNameError:P,agentError:W,options:T,policy:D,setPolicy:F}=xs(e),L=t.jsxs(t.Fragment,{children:[t.jsx("p",{className:"rp-note",children:s("nodes.note")}),t.jsx(Te,{error:r,onRetry:u}),t.jsx(ss,{model:o}),t.jsx(ts,{model:c})]});return t.jsxs("div",{className:"rp-page",children:[n?t.jsx(Ln,{keepMounted:!0,label:s("nav.nodes"),value:a,onChange:d,items:[{id:"list",label:s("nodes.tab.list"),content:L},{id:"latency",label:s("nodes.tab.latency"),content:t.jsx(ns,{})}]}):L,t.jsxs(Dn,{title:l,narrow:!0,isOpen:i!==null&&!b,onOpenChange:N=>{N||p(null)},footer:N=>t.jsxs(t.Fragment,{children:[t.jsx(A,{onPress:N,children:s("ui.cancel")}),t.jsx(A,{accent:!0,isDisabled:!v||S,isPending:f,onPress:()=>void x(N),children:_})]}),children:[m&&t.jsx($n,{takeFocus:!0,children:m.text},m.id),i?.kind==="provider"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:s("nodes.addProviderHelp")}),t.jsx(z,{isDisabled:f,label:s("nodes.name"),value:h.name,placeholder:"sub-a",onChange:N=>y({...h,name:N})}),t.jsx(z,{isDisabled:f,label:s("nodes.url"),value:h.value,placeholder:"https://example.org/sub?token=…",onChange:N=>y({...h,value:N})}),T?.intervals&&t.jsx(me,{label:s("nodes.interval"),items:T.intervals,value:T.interval,isDisabled:f,onChange:N=>y({...h,interval:N})}),T?.agent!==void 0&&t.jsx(z,{isDisabled:f,label:s("nodes.agent"),value:h.agent,placeholder:T.agent,error:W??void 0,spellCheck:!1,onChange:N=>y({...h,agent:N})}),T?.cache!=null&&t.jsxs(t.Fragment,{children:[t.jsx(Rn,{isSelected:T.cache,isDisabled:f,onChange:N=>y({...h,cache:N}),children:s("nodes.cache")}),t.jsx("span",{className:"rp-label",children:s("nodes.cacheHelp")})]})]}),i?.kind==="group"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:R}),t.jsx(z,{isDisabled:f,label:s("nodes.name"),value:h.name,placeholder:"hk",spellCheck:!1,description:s("arrange.groupNameHint"),error:P??void 0,onChange:N=>y({...h,name:N})}),t.jsx(Jn,{value:D,onChange:F,isDisabled:f})]}),i?.kind==="node"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:s("nodes.addNodeHelp")}),t.jsx(z,{isDisabled:f,label:s("nodes.name"),value:h.name,placeholder:"hk-03",onChange:N=>y({...h,name:N})}),t.jsx(z,{isDisabled:f,label:s("nodes.link"),value:h.value,placeholder:"vless://…",onChange:N=>y({...h,value:N})})]})]}),t.jsx(Gn,{title:l,isOpen:b,onCancel:()=>p(null),confirmLabel:_,isPending:f,isDisabled:S,error:m,onConfirm:()=>void x(()=>p(null)),children:t.jsx("p",{className:"rp-label",children:s(i?.kind==="removeProvider"?"nodes.removeProviderHelp":"nodes.removeNodeHelp")})})]})}export{Ws as Nodes};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-CF-Y3hZu.js b/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-CF-Y3hZu.js
new file mode 100644
index 000000000..da1ee3c3a
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Nodes-CF-Y3hZu.js
@@ -0,0 +1,5 @@
+import{r as j,j as t}from"./vendor-react-Bf71BWbF.js";import{u as V,aM as Ye,B as F,cx as ve,aP as q,a5 as _e,a8 as Se,a7 as ee,a9 as Ke,a as ie,aB as Xe,E as Te,j as Ze,af as en,aT as H,bt as Ce,bu as nn,bw as sn,aG as an,cr as Le,b1 as tn,$ as De,aE as ne,aH as on,bj as Re,aC as rn,bz as ln,ae as $e,T as Q,b2 as me,y as Ge,N as dn,q as se,Q as cn,P as ke,C as un,d1 as Ae,d2 as mn,d3 as Fe,as as pn,aY as bn,am as vn,an as hn,a0 as Ne,aq as fn,ap as ce,a1 as ae,b3 as gn,cs as xn,a2 as he,bb as C,cB as pe,cO as fe,b as ge,cN as jn,bc as yn,J as We,d4 as kn,cH as Nn,d5 as we,cA as wn,aa as Pn,d6 as Mn,d7 as _n,cy as Sn,d8 as Tn,be as Cn,bf as Ln,d9 as Dn,cC as Rn,bn as $n,ac as Gn,I as An,cw as Fn,cW as Wn}from"./index-CXHBmSa5.js";import{F as Bn}from"./FactStrip-BgQ_tYB6.js";import{u as In,C as En,p as On}from"./layout-BRLew_nj.js";import{D as Be,c as Hn}from"./Table-D0NFHHNQ.js";import{T as qn}from"./TimeCell-gSIuLEFc.js";import{A as Vn}from"./AddCircle-Db3HxlxQ.js";import{u as zn}from"./outbounds-f8QoVoCV.js";import{p as Un,b as Qn}from"./policyText-CAFy3qpo.js";import{a as Ie}from"./setup-B5f1cfyO.js";import{$ as Jn}from"./useFilter-DZ8TXqn_.js";import{p as Yn}from"./probe-C8ejAKwA.js";import{P as Kn}from"./PolicyPicker-DSSmYroN.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";function Pe({kind:e,color:s}){return t.jsx("i",{className:"rp-marker "+e,style:s?{color:s}:void 0,"aria-hidden":"true"})}function Xn({label:e,groups:s,legend:n,max:a,fmt:l,limit:o=10,showAll:c}){const r=V(),u=Ye(),{ref:d,tip:p,show:m,hide:h}=In(),[k,b]=j.useState(new Set),i=[0,a/4,a/2,3*a/4,a],v=g=>Math.min(100,g/a*100);return t.jsxs("div",{className:"rp-markerplot rp-chart-hover",ref:d,onPointerLeave:h,role:"group","aria-label":e,"aria-describedby":u,children:[t.jsx("ul",{className:"legend",children:n.map(g=>t.jsxs("li",{children:[t.jsx(Pe,{kind:g.kind}),g.label]},g.kind))}),t.jsxs("div",{className:"axis","aria-hidden":"true",children:[t.jsx("span",{}),t.jsx("div",{className:"scale",children:i.map(g=>t.jsx("span",{style:{insetInlineStart:`${v(g)}%`},children:l(g)},g))}),t.jsx("span",{})]}),s.map(g=>t.jsxs("section",{"aria-label":g.label,children:[s.length>1&&t.jsx("h4",{className:"rp-label",children:g.label}),(k.has(g.id)?g.rows:g.rows.slice(0,o)).map(x=>{const N=Object.values(x.values).filter(M=>M!==void 0),T=v(Math.min(...N)),D=v(Math.max(...N));return t.jsxs("div",{className:"row",onPointerMove:M=>m(M,[x.label,...x.details]),children:[t.jsx("span",{className:"name",children:x.label}),t.jsxs("div",{className:"track",role:"img","aria-label":x.label+r("ui.separator")+x.description,children:[i.map(M=>t.jsx("i",{className:"grid",style:{insetInlineStart:`${v(M)}%`}},M)),D>T&&t.jsx("i",{className:"span",style:{insetInlineStart:`${T}%`,width:`${D-T}%`}}),["tick","diamond","dot"].map(M=>x.values[M]===void 0?null:t.jsx("span",{className:"at "+M+(x.values[M]>a?" over":""),style:{insetInlineStart:`${v(x.values[M])}%`},children:t.jsx(Pe,{kind:M,color:M==="dot"?x.tone:void 0})},M))]}),t.jsx("span",{className:"value",children:x.text})]},x.id)}),!k.has(g.id)&&g.rows.length>o&&t.jsx("div",{className:"row more",children:t.jsx(F,{quiet:!0,small:!0,onPress:()=>b(x=>new Set([...x,g.id])),children:c(g.rows.length)})}),g.notes.map(x=>t.jsx("p",{className:"rp-note note",children:x},x))]},g.id)),t.jsx(En,{tip:p})]})}function Zn(e,s,n){const a=new Map((s??[]).map(r=>[r.id,r.name])),l=new Map,o=(r,u)=>{let d=l.get(r);return d||l.set(r,d={id:r,label:u,rows:[],missing:[]}),d};for(const r of e){const u=ve(r),d=n==="protocol"?[["protocol:"+(r.protocol??""),r.protocol??null]]:r.group_ids.length?r.group_ids.map(p=>["group:"+p,a.get(p)??p]):[["group:",null]];for(const[p,m]of d){const h=o(p,m);u?.state==="healthy"&&u.latency_ms!==null?h.rows.push({id:r.id,name:r.name,latest:u.latency_ms,moving:u.moving_avg_ms,avg10:u.avg10_ms}):h.missing.push({id:r.id,name:r.name,state:u?.state==="unavailable"?"unavailable":"unmeasured"})}}const c=[...l.values()];for(const r of c)r.rows.sort((u,d)=>u.latest-d.latest||q(u.name,d.name)),r.missing.sort((u,d)=>q(u.name,d.name));return c.sort((r,u)=>(r.label===null?1:0)-(u.label===null?1:0)||q(r.label??"",u.label??""))}function es(e){const s=e.flatMap(n=>n.rows);return{moving:s.some(n=>n.moving!==null),avg10:s.some(n=>n.avg10!==null)}}function ns(e){const s=e.flatMap(l=>l.rows.flatMap(o=>[o.latest,o.moving??o.latest])).sort((l,o)=>l-o),n=Math.max(10,(On(s,90)??0)*1.25),a=n<=100?20:n<=500?100:n<=2e3?500:1e3;return Math.ceil(n/a)*a}function ss(){const e=_e().data?.resources,s=Se(ee(e,"nodes",{whileLoading:!0})),n=Ke(ee(e,"groups",{whileLoading:!1})),[a,l]=j.useState("group"),o=j.useMemo(()=>Zn(s.data??[],n.data,a),[s.data,n.data,a]);return{nodes:s,by:a,setBy:l,view:o}}const ue=6;function as(){const e=V(),s=ie(),n=Xe(),{nodes:a,by:l,setBy:o,view:c}=ss();if(a.error&&!a.data)return t.jsx(Te,{error:a.error,onRetry:a.refetch});if(!a.data)return t.jsx(Ze,{});if(!a.data.length)return t.jsx(en,{children:e("ui.empty")});const r={ok:n.positive,warn:n.notice,err:n.negative},u=es(c),d=[...new Map(c.flatMap(b=>b.rows).map(b=>[b.id,b])).values()].sort((b,i)=>b.latest-i.latest),p=new Set(c.flatMap(b=>b.missing.filter(i=>i.state==="unavailable").map(i=>i.id))).size,m=d.length?[{label:e("nodes.latency.lowest"),icon:t.jsx(Ce,{}),tint:"c2",value:d[0].name,caption:H(d[0].latest,e)},{label:e("nodes.latency.highest"),icon:t.jsx(nn,{}),tint:"c4",value:d[d.length-1].name,caption:H(d[d.length-1].latest,e)},{label:e("nodes.latency.unavailable"),value:e("nodes.latency.count",{n:p}),icon:t.jsx(sn,{}),tint:"c5",tone:p?"negative":void 0}]:[],h=b=>{const i=De(s,b.slice(0,ue).map(v=>v.name));return b.length>ue?`${i} ${e("nodes.latency.andMore",{n:b.length-ue})}`:i},k=b=>{const i=b.filter(g=>g.state==="unavailable"),v=b.filter(g=>g.state==="unmeasured");return[...i.length?[e("nodes.latency.unavailableList",{n:i.length,names:h(i)})]:[],...v.length?[e("nodes.latency.unmeasuredList",{n:v.length,names:h(v)})]:[]]};return t.jsxs("div",{className:"rp-chart-page",children:[t.jsx(Bn,{facts:m}),t.jsx(an,{title:e("ui.nodeLatency"),note:e("nodes.latency.sample",{n:a.data.length}),aside:t.jsx(tn,{label:e("nodes.latency.by"),value:l,onChange:b=>o(b),items:[["group",e("nodes.latency.byGroup")],["protocol",e("nodes.latency.byProtocol")]]}),children:t.jsx(Xn,{label:e("ui.nodeLatency"),max:ns(c),fmt:b=>H(b,e),showAll:b=>e("nodes.latency.showAll",{n:b}),legend:[{kind:"dot",label:e("nodes.latency.latest")},...u.moving?[{kind:"diamond",label:e("nodes.latency.moving")}]:[],...u.avg10?[{kind:"tick",label:e("nodes.latency.avg10")}]:[]],groups:c.map(b=>({id:b.id,label:b.label??e(l==="group"?"nodes.latency.noGroup":"nodes.latency.noProtocol"),rows:b.rows.map(i=>{const v=[e("ui.valuePair",{label:e("nodes.latency.latest"),value:H(i.latest,e)}),...u.moving?[e("ui.valuePair",{label:e("nodes.latency.moving"),value:H(i.moving,e)})]:[],...u.avg10?[e("ui.valuePair",{label:e("nodes.latency.avg10"),value:H(i.avg10,e)})]:[]];return{id:i.id,label:i.name,values:{dot:i.latest,diamond:i.moving??void 0,tick:i.avg10??void 0},text:H(i.latest,e),tone:r[Le(i.latest)],description:v.join(e("ui.separator")),details:v}}),notes:k(b.missing)}))})})]})}function ts({model:e}){const s=V();return t.jsxs(t.Fragment,{children:[e.canManage&&t.jsxs("div",{className:"rp-toolbar",children:[t.jsx("span",{className:"rp-grow"}),t.jsx(F,{small:!0,onPress:e.onAdd,children:s("nodes.addProvider")})]}),t.jsx(Be,{label:s("nodes.providers"),loading:e.loading,rows:e.rows,height:280,fit:!0,selected:e.selected,onSelect:e.onSelect,selectOnFocus:!0,empty:s("nodes.noProviders"),cols:[{id:"name",label:s("nodes.provider"),minWidth:140,grow:2,isRowHeader:!0,render:n=>t.jsx("span",{className:"rp-chain",children:t.jsx(ne,{text:n.url,children:n.name})})},{id:"kind",label:s("nodes.kindLabel"),minWidth:150,grow:0,drop:5,render:n=>t.jsx(on,{children:n.kind})},{id:"count",label:s("nodes.count"),minWidth:80,grow:0,align:"end",drop:6,render:n=>n.count},{id:"usage",label:s("nodes.usage"),minWidth:200,drop:2,render:n=>n.usage},{id:"updated",label:s("nodes.updated"),minWidth:140,drop:3,render:n=>t.jsx(qn,{at:n.updatedAt})},{id:"interval",label:s("nodes.interval"),minWidth:130,grow:0,drop:4,render:n=>n.hasInterval&&e.writable?t.jsx(ne,{text:e.sourceTip,children:t.jsx(Re,{quiet:!0,label:n.intervalLabel,value:n.intervalValue,isDisabled:e.sourceBusy,onChange:n.setInterval,items:n.intervals,children:n.interval})}):n.interval},{id:"expires",label:s("nodes.expires"),minWidth:140,drop:1,render:n=>n.expires},{id:"status",label:s("ui.state"),minWidth:96,grow:0,drop:7,render:n=>n.status?t.jsx(rn,{small:!0,tone:n.tone,children:t.jsx(ne,{text:n.error,children:n.status})}):"—"},{id:"actions",label:s("ui.actions"),minWidth:e.canManage?112:88,grow:0,render:n=>t.jsxs("span",{className:"rp-chain",children:[n.refreshable&&t.jsx(F,{small:!0,quiet:!0,icon:!0,isPending:n.refreshing,isDisabled:n.refreshDisabled,label:n.refreshLabel,onPress:n.refresh,children:t.jsx(ln,{className:"rp-spin-on-press"})}),n.removable&&t.jsx(F,{small:!0,quiet:!0,icon:!0,isDisabled:e.busy,label:n.removeLabel,onPress:n.remove,children:t.jsx($e,{})})]})}]})]})}const Ee=j.createContext(null);function os({row:e}){const s=j.useContext(Ee);return t.jsx(F,{small:!0,quiet:!0,icon:!0,isPending:s===e.id,isDisabled:!!s,label:e.probeLabel,onPress:e.probe,children:t.jsx(Ce,{})})}function rs({model:e}){const s=V(),{canManage:n,writable:a,sourceBusy:l,busy:o}=e,c=j.useMemo(()=>[{id:"name",label:s("nodes.node"),minWidth:150,grow:2,isRowHeader:!0,sortable:!0,render:r=>t.jsx("span",{className:"rp-chain",children:t.jsx(ne,{children:r.name})})},{id:"protocol",label:s("nodes.protocol"),minWidth:144,grow:0,drop:2,sortable:!0,render:r=>r.protocol},{id:"latency",label:s("nodes.latency"),minWidth:96,grow:0,align:"end",sortable:!0,render:r=>t.jsx("span",{className:r.latencyClass,children:r.latency})},{id:"groups",label:s("nodes.groups"),minWidth:200,drop:1,render:r=>t.jsx(ne,{children:r.groups})},{id:"actions",label:s("ui.actions"),minWidth:n?108:72,grow:0,render:r=>t.jsxs("span",{className:"rp-chain",children:[r.canProbe&&t.jsx(os,{row:r}),a&&t.jsx(Re,{quiet:!0,chevron:!1,label:r.joinLabel,isDisabled:l,items:r.menu,onAction:r.join,children:t.jsx(Vn,{})}),r.removable&&t.jsx(F,{small:!0,quiet:!0,icon:!0,isDisabled:o,label:r.removeLabel,onPress:r.remove,children:t.jsx($e,{})})]})}],[s,n,a,l,o]);return t.jsxs(t.Fragment,{children:[e.writable&&e.sourceTip&&t.jsx("p",{className:"rp-note",children:e.sourceTip}),t.jsxs("div",{className:"rp-toolbar",children:[t.jsx(Q,{label:s("nodes.search"),search:!0,value:e.search,width:240,onChange:e.setSearch}),t.jsx(me,{label:s("nodes.group"),side:!0,value:e.group,onChange:e.setGroup,items:e.groups}),t.jsx(me,{label:s("nodes.protocol"),side:!0,value:e.protocol,onChange:e.setProtocol,items:e.protocols}),t.jsx("span",{className:"rp-label",children:e.shown}),t.jsx("span",{className:"rp-grow"}),e.canManage&&t.jsx(F,{small:!0,onPress:e.onAdd,children:s("nodes.addNode")})]}),t.jsx(Ee.Provider,{value:e.probeBusy,children:t.jsx(Be,{label:e.label,loading:e.loading,rows:e.rows,height:520,empty:s("nodes.empty"),sort:e.sort,onSort:e.setSort,cols:c})})]})}function is(e){const s=/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(e.trim());if(!s)return null;const n={ms:1/1e3,s:1,m:60,h:3600};return Math.ceil(Number(s[1])*(n[s[2]??"s"]??1))}function re(e){if(!e)return null;try{return new URL(e).hostname||null}catch{return null}}function ls(e){const s=un(e).trim(),{tokens:n}=Ge(s),a=n[0];if(!a)return null;const l=s.slice(a.from,a.to),o=n[1],c=o&&s.slice(o.from,o.to)===":"&&!s.slice(o.to).startsWith("//"),r=c?o.to:0,u=n.find(b=>b.from>=r);if(!u)return null;const d=u.kind==="quoted";let p=d?se(s.slice(u.from,u.to)):s.slice(r).trim(),m=c?se(l):null;if(!m){const b=p.indexOf(":");b!==-1&&!p.startsWith("://",b)?(m=p.slice(0,b).trim(),p=p.slice(b+1)):m=re(p)}const h=d?s.slice(u.to).trim():"",k=h.startsWith("(")&&h.endsWith(")")?se(h.slice(1,-1)):null;return h&&k===null?null:m?{tag:m,url:p,ua:k}:null}function Oe(e){const{blocks:s,tokens:n}=Ge(e),a=[];for(const l of s.filter(o=>o.name==="subscription"))for(let o=0;o=l.close||c.depth!==l.depth+1||c.kind==="comment")continue;const r=e.lastIndexOf(`
+`,c.from-1)+1,u=/^[ \t]*$/.test(e.slice(r,c.from))?r:c.from,d=l.children.find(i=>i.from===c.from);if(d){for(;n[o+1]?.fromx.name==="url"),g=i.find(x=>x.name==="interval");a.push({from:u,to:d.to,block:d,tag:d.name,host:v?re(se(v.value)):null,interval:g?is(se(g.value)):null,fields:i,parts:null});continue}const p=n[o+1];p&&e.slice(p.from,p.to)===":"&&!e.slice(p.to).startsWith("//")&&(o+=2);const m=n[o];if(!m||m.from>=l.close)break;if(m.kind!=="quoted")for(;n[o+1]?.from===n[o].to&&!/[(){}]/.test(e.slice(n[o+1].from,n[o+1].to));)o++;if(e[n[o+1]?.from]==="(")for(o++;n[o+1]&&!(e[n[o].from]===")"&&n[o].parens===1);)o++;let h=n[o].to,k;n[o+1]?.kind==="comment"&&n[o+1].line===n[o].line&&(k=e.slice(n[o+1].from,n[o+1].to),h=n[++o].to);const b=ls(e.slice(u,h));b&&a.push({from:u,to:h,tag:b.tag,host:re(b.url),interval:null,fields:[],parts:b,comment:k})}return a}function ds(e){return Oe(e).map(({tag:s,host:n,interval:a})=>({tag:s,host:n,interval:a}))}function cs(e,s,n){const a=Oe(e).find(u=>u.tag===s);if(!a||a.interval===n)return e;const l=e.slice(a.from,a.to).match(/^[ \t]*/)?.[0]??" ",o=l+(l.includes(" ")?" ":" ");if(a.parts){const u=[`${l}${cn(s)}: {`,`${o}url: ${ke(a.parts.url)}`];return a.parts.ua!==null&&u.push(`${o}ua: ${ke(a.parts.ua)}`),u.push(`${o}interval: '${n}s'`,`${l}}${a.comment?" "+a.comment:""}`),e.slice(0,a.from)+u.join(`
+`)+e.slice(a.to)}const c=a.fields.find(u=>u.name==="interval");if(c)return e.slice(0,c.valueFrom)+` '${n}s'`+e.slice(c.valueTo);if(!a.block)return e;const r=e.lastIndexOf(`
+`,a.block.close-1)+1;return e.slice(0,r)+`${o}interval: '${n}s'
+`+e.slice(r)}function us(e,s,n,a){const l=ve(e),o=l?.state==="healthy"&&l.latency_ms!=null;return{id:e.id,name:e.name,protocol:e.protocol??"—",latency:o?H(l.latency_ms,a):l?.state==="unavailable"?a("ui.unavailable"):"—",latencyClass:o?`ms ${Le(l.latency_ms)}`:l?.state==="unavailable"?"ms err":"ms",groups:e.group_ids.length?De(n,e.group_ids.map(c=>s.get(c)??c)):"—",probeLabel:a("nodes.probe",{name:e.name}),joinLabel:a("nodes.joinGroup",{name:e.name}),removeLabel:a("nodes.remove",{name:e.name})}}const ms=e=>gn(ve(e));function ps(e,s,n,a){const l=new Map;for(const i of s){if(!i.provider_id||!i.subscription_tag)continue;const v=l.get(i.provider_id)??new Set;v.add(i.subscription_tag),l.set(i.provider_id,v)}const o=i=>{const v=l.get(i);return v?.size===1?[...v][0]:void 0},c=i=>{const v=re(i.url_redacted),g=v?n.filter(x=>x.host===v):[];return g.length===1?g[0].tag:void 0},r=new Map,u=e.filter(i=>i.kind==="subscription");for(const i of u){const v=o(i.id)??c(i);v&&r.set(i.id,v)}const d=u.filter(i=>!r.has(i.id)),p=new Set(r.values()),m=n.filter(i=>!p.has(i.tag));d.length===1&&m.length===1&&r.set(d[0].id,m[0].tag);const h=e.map(i=>{const v=o(i.id);return{...i,displayName:r.get(i.id)??i.name,configTag:i.kind==="subscription"&&v&&n.filter(g=>g.tag===v).length===1?v:void 0}}),k={builtin:0,unattributed:0};for(const i of s)i.provider_id==null&&k[Ae(i)]++;const b=[];for(const i of["builtin","unattributed"]){const v=k[i];v&&b.push({id:mn(i,e),name:a(i==="builtin"?"nodes.kind.builtin":"nodes.kind.unattributed"),kind:i,url_redacted:null,node_count:v,updated_at:null,expires_at:null,traffic:null,status:"ok",last_error:null})}return{list:[...b,...h]}}function bs(e,s){return s!==null&&e.some(n=>n.id===s)?s:(e.find(n=>n.kind!=="builtin"&&n.kind!=="unattributed")??e[0])?.id??null}function vs(e,s,n){return e.filter(a=>s===void 0||(s===null?a.provider_id==null&&Ae(a)==="builtin"==(n==="builtin"):a.provider_id===s))}function hs(e,s,n,a,l,o){const c=s.trim(),r=e.filter(m=>(!c||o(m.name,c))&&(!n||m.group_ids.includes(n))&&(!a||m.protocol===a)),u=l.direction==="ascending"?1:-1,d=l.column==="latency"?new Map(r.map(m=>[m.id,ms(m)])):new Map,p={name:(m,h)=>q(m.name,h.name),protocol:(m,h)=>q(m.protocol??"",h.protocol??""),latency:(m,h)=>xn(d.get(m.id),d.get(h.id))||q(m.name,h.name)};return r.sort((m,h)=>u*(p[l.column]??p.name)(m,h))}const be=[3600,21600,43200,86400];function xe(e,s,n){return e===0?n("nodes.manualOnly"):be.includes(e)?n("nodes.everyHours",{n:e/3600}):pn(String(e),s)}function He(e,s,n){return[0,...be,...e===null||e===0||be.includes(e)?[]:[e]].map(a=>({id:String(a),label:xe(a,s,n)}))}function fs(e,s){const n={name:e.name.trim(),kind:"subscription",url:e.value.trim()},a=Number(e.interval);s?.update_interval!==void 0&&e.interval&&a!==s.update_interval&&(n.update_interval=a);const l=e.agent.trim();return s?.user_agent!==void 0&&l&&l!==s.user_agent&&(n.user_agent=l),s?.cache!==void 0&&e.cache!==null&&e.cache!==s.cache&&(n.cache=e.cache),n}function gs(e,s,n,a){const l={subscription:"nodes.kind.subscription",file:"nodes.kind.file",inline:"nodes.kind.inline",builtin:"nodes.kind.builtin",unattributed:"nodes.kind.unattributed"},o={ok:"nodes.status.ok",stale:"nodes.status.stale",error:"nodes.status.error"},c={ok:"ok",stale:"warn",error:"err"},r=e.kind==="builtin"||e.kind==="unattributed",u=e.traffic?bn(e.traffic.upload_bytes,e.traffic.download_bytes):null,d=e.kind==="subscription"?s:void 0,p=e.displayName??e.name;return{id:e.id,name:p,url:e.url_redacted??void 0,kind:Ne(l,e.kind,a),count:ae(e.node_count,n),usage:u===null?"—":e.traffic?.total_bytes?a("ui.fraction",{part:ce(u,n),whole:ce(e.traffic.total_bytes,n)}):ce(u,n),updatedAt:r?null:e.updated_at,expires:e.expires_at?fn(e.expires_at,n):"—",interval:d==null?"—":xe(d,n,a),intervalValue:d==null?"":String(d),hasInterval:d!==void 0,intervalLabel:a("nodes.intervalOf",{name:p}),intervals:d===void 0?[]:He(d,n,a),status:r?null:Ne(o,e.status,a),tone:c[e.status],error:e.last_error?vn(hn(e.last_error.code,e.last_error.message,a),a):void 0,refreshLabel:a("nodes.refresh",{name:p}),removeLabel:a("nodes.remove",{name:p})}}const qe=e=>/^[a-z][a-z0-9+.-]*:\/\/\S+$/i.test(e.trim());function xs(e,s,n,a){const l=s.trim();return e!=="provider"&&e!=="node"||!l&&!n.trim()?null:l?e==="node"?qe(n)?null:a("nodes.linkInvalid"):Fe(l)?Ie(n)?null:a("nodes.urlInvalid"):a("nodes.nameInvalid"):a("nodes.nameMissing")}function js(e){const s=V(),n=he[ie()],{refresh:a}=e,l=new Map(e.entries.map(c=>[c.tag,c.interval]));return{rows:e.rows.map(c=>({...gs(c,c.configTag?l.get(c.configTag):void 0,n,s),refreshable:c.kind==="subscription"&&e.canRefresh,refreshing:a.busy===c.id,refreshDisabled:!!a.busy,refresh:()=>void a.refresh(c.id).then(r=>{r&&("degraded"in r?C("info",s("nodes.refreshedDegraded",{name:c.name})):C("positive",s("nodes.refreshed",{name:c.name,n:ae(r.node_count,n)})))},r=>fe(r,s,s("nodes.refreshFailed",{name:c.name}))),removable:e.canManage&&(c.kind==="subscription"||c.kind==="file"),remove:()=>{(c.kind==="subscription"||c.kind==="file")&&e.onRemove(c)},setInterval:r=>{if(!c.configTag)return;const u=Number(r);e.source.apply(d=>cs(d,c.configTag,u)).then(d=>{d.kind==="ok"&&C("positive",s("nodes.intervalSet",{name:c.name,interval:xe(u,n,s)}));const p=pe(d,s);p&&C(p.kind,p.text,{detail:p.detail})})}})),loading:e.loading,selected:e.selected,onSelect:e.onSelect,canManage:e.canManage,busy:e.busy,writable:e.source.writable,sourceBusy:e.source.busy||!e.source.main,sourceTip:e.source.error?ge(e.source.error,s):void 0,onAdd:e.onAdd}}function ys(e){const{nodes:s,names:n,providers:a,source:l,query:o,reload:c,joinGroup:r,onNewGroup:u,onRemove:d,canManage:p}=e,m=V(),h=ie(),k=he[h],b=jn(c),[i,v]=j.useState(o??"");yn(o,f=>v(f??""));const[g,x]=j.useState(""),[N,T]=j.useState(""),[D,M]=j.useState({column:"name",direction:"ascending"}),W=j.useMemo(()=>[...new Set(s.flatMap(f=>f.group_ids))].sort((f,P)=>q(n.get(f)??f,n.get(P)??P)).map(f=>({id:f,label:n.get(f)??f})),[s,n]),$=j.useMemo(()=>[...new Set(s.map(f=>f.protocol??""))].filter(Boolean).sort(q).map(f=>({id:f,label:f})),[s]),S=W.some(f=>f.id===g)?g:"",B=$.some(f=>f.id===N)?N:"",{contains:L}=Jn({sensitivity:"base"}),G=j.useMemo(()=>hs(s,i,S,B,D,L),[s,i,S,B,D,L]),w=j.useMemo(()=>We(l.main?.content??"").map(f=>({...f,names:new Set(kn(f))})),[l.main?.content]),I=j.useMemo(()=>new Map(s.map(f=>[f.id,new Set(f.group_ids.map(P=>n.get(P)??P))])),[s,n]),K=j.useMemo(()=>new Set(a.filter(f=>f.kind==="inline").map(f=>f.id)),[a]),{probe:z,canProbe:J,busy:le}=b,Y=j.useCallback(f=>({...us(f,n,h,m),canProbe:J&&!Nn(f.protocol),probe:()=>void z(f.id).then(P=>{if(!P)return;const{kind:de,text:oe}=Yn(P,f.id,f.name,m);C(de,oe)},P=>fe(P,m,m("nodes.probeError",{name:f.name}))),menu:()=>[...w.filter(P=>!P.names.has(f.name)&&!I.get(f.id)?.has(P.name)).map(P=>({id:P.name,label:P.name,desc:Un(P.policy,m)})),{id:"/new",label:m("nodes.newGroup")}],join:P=>P==="/new"?u(f):r(f,P),removable:p&&typeof f.provider_id=="string"&&K.has(f.provider_id),remove:()=>d(f)}),[n,h,J,z,m,w,I,u,r,p,K,d]),X=j.useMemo(()=>({build:Y,rows:new WeakMap}),[Y]),te=j.useMemo(()=>Hn(X.rows,G,X.build),[X,G]);return{rows:te,probeBusy:le,search:i,setSearch:v,group:S,setGroup:x,protocol:B,setProtocol:T,sort:D,setSort:M,groups:[{id:"",label:m("nodes.anyGroup")},...W],protocols:[{id:"",label:m("nodes.anyProtocol")},...$],shown:m("ui.fraction",{part:ae(te.length,k),whole:ae(s.length,k)}),loading:e.loading,label:e.label,canManage:p,busy:e.busy,writable:l.writable,sourceBusy:l.busy||!l.main,sourceTip:l.error?ge(l.error,m):void 0,onAdd:e.onAdd}}const Me={name:"",value:"",interval:"",agent:"",cache:null};function ks({go:e,query:s}){const n=V(),[a,l]=j.useState(null),[o,c]=j.useState(Me),[r,u]=j.useState(we[0].id),d=j.useRef(0),p=j.useRef(null),[m,h]=j.useState(null),[k,b]=j.useState(null),i=wn(!!a&&!!(o.name||o.value),()=>{d.current++,l(null)}),v=j.useCallback(y=>{d.current++,c(Me),u(we[0].id),b(null),l(y)},[]),g=he[ie()],x=_e().data?.resources,N=Pn(ee(x,"providers",{whileLoading:!0})),T=Se(ee(x,"nodes",{whileLoading:!0})),D=zn(),{refetch:M}=N,{refetch:W}=T,$=j.useCallback(()=>{M(),W()},[M,W]),S=Mn($),B=_n($),L=Sn(),G=j.useMemo(()=>ds(L.main?.content??""),[L.main?.content]),w=j.useMemo(()=>new Set(We(L.main?.content??"").map(y=>y.name)),[L.main?.content]),{list:I}=j.useMemo(()=>ps(N.data?.providers??[],T.data??[],G,n),[N.data,T.data,G,n]),K=j.useMemo(()=>new URLSearchParams(s),[s]),z=bs(I,K.get("provider")),J=I.find(y=>y.id===z)??null,le=j.useMemo(()=>{const y=I.find(R=>R.id===z);return vs(T.data??[],y?.kind==="builtin"||y?.kind==="unattributed"?null:y?.id,y?.kind)},[T.data,I,z]),{apply:Y}=L,X=j.useCallback((y,R)=>{Y(U=>Tn(U,R,[y.name])).then(U=>{U.kind==="ok"&&C("positive",n("nodes.joined",{name:y.name,group:R}));const _=pe(U,n);_&&C(_.kind,_.text,{detail:_.detail})})},[Y,n]),te=j.useCallback(()=>v({kind:"node"}),[v]),f=j.useCallback(y=>v({kind:"group",item:y}),[v]),P=j.useCallback(y=>v({kind:"removeNode",item:y}),[v]),de=async y=>{if(!a||p.current)return;p.current=a,h(a);const R=d.current,U=_=>{d.current===R?b(A=>({id:(A?.id??0)+1,text:_})):C("negative",_)};try{if(a.kind==="provider"){const _=await S.addProvider(fs(o,E));if(!_)return;const A=o.name.trim();if(x?.providers.can_refresh){d.current===R&&(i.clear(),y());const Z=()=>void B.refresh(_.id).then(O=>{O&&("degraded"in O?C("info",n("nodes.refreshedDegraded",{name:A})):C("positive",n("nodes.addedRefreshed",{name:A,n:ae(O.node_count,g)})))},O=>fe(O,n,n("nodes.addedRefreshFailed",{name:A}),{label:n("ui.retry"),onAction:Z,closeOnAction:!0}));Z();return}C("positive",n("nodes.added",{name:A}))}else if(a.kind==="node"){const _=await S.addNode({name:o.name.trim(),link:o.value.trim()});if(!_)return;C("positive",n("nodes.added",{name:_.name}))}else if(a.kind==="group"){const _=o.name.trim(),A=a.item.name,Z=await Y(Je=>Dn(Je,[{kind:"createGroup",group:_,policy:r},{kind:"addNode",group:_,value:A}])),O=pe(Z,n);if(O&&U(Rn(O,n)),Z.kind!=="ok")return;C("positive",n("nodes.joined",{name:A,group:_}))}else if(a.kind==="removeProvider"){if(!await S.removeProvider(a.item.id))return;C("positive",n("nodes.removed",{name:a.item.name}))}else{if(!await S.removeNode(a.item.id))return;C("positive",n("nodes.removed",{name:a.item.name}))}d.current===R&&(i.clear(),y())}catch(_){U(ge(_,n))}finally{p.current=null,h(null)}},oe=a?.kind==="removeProvider"||a?.kind==="removeNode",Ve=a===null?"":a.kind==="provider"?n("nodes.addProvider"):a.kind==="node"?n("nodes.addNode"):a.kind==="group"?n("nodes.newGroup"):n(a.kind==="removeProvider"?"nodes.removeProviderTitle":"nodes.removeNodeTitle",{name:a.item.name}),je=a?.kind==="group"?Qn(o.name.trim(),w,n):null,E=x?.providers.create_options,ye=/^[\x20-\x7E]{0,256}$/.test(o.agent.trim())?null:n("nodes.agentInvalid"),ze=a?.kind==="provider"?Fe(o.name.trim())&&Ie(o.value)&&!ye:a?.kind==="node"?o.name.trim()!==""&&qe(o.value):a?.kind==="group"?je===null:!0,Ue=js({rows:I,loading:N.loading&&!N.data,selected:z,onSelect:y=>{if(!y)return;const R=new URLSearchParams(s);R.set("provider",y),e("nodes",R.toString(),{replace:!0})},canManage:!!x?.providers.can_manage,canRefresh:!!x?.providers.can_refresh,busy:!!S.busy,source:L,entries:G,reload:$,refresh:B,onAdd:()=>v({kind:"provider"}),onRemove:y=>v({kind:"removeProvider",item:y})}),Qe=ys({nodes:le,providers:N.data?.providers??[],names:D,loading:T.loading&&!T.data,label:J?n("nodes.of",{name:J.displayName??J.name}):n("nav.nodes"),query:K.get("q"),source:L,canManage:!!x?.nodes.can_manage,busy:!!S.busy,reload:W,joinGroup:X,onAdd:te,onNewGroup:f,onRemove:P});return{measured:ee(x,"nodes",{whileLoading:!0}),tab:Ln(s,["list","latency"],"list"),setTab:y=>e("nodes",Cn(s,y,"list")),providerTable:Ue,nodeTable:Qe,error:N.error??T.error,reload:$,dialog:a,setDialog:y=>{d.current++,b(null),l(y)},problem:k,form:o,setForm:y=>{p.current!==a&&c(y)},removing:oe,dialogTitle:Ve,formValid:ze,formReason:xs(a?.kind,o.name,o.value,n),submit:de,pending:a!==null&&m===a,submitting:m!==null,submitLabel:oe?n("nodes.remove",{name:a.item.name}):a?.kind==="group"?n("nodes.join"):n("nodes.add"),groupHelp:a?.kind==="group"?n("nodes.newGroupHelp",{name:a.item.name}):"",groupNameError:o.name.trim()?je:null,agentError:ye,options:E&&{intervals:E.update_interval===void 0?null:He(E.update_interval,g,n),interval:o.interval||String(E.update_interval),agent:E.user_agent,cache:E.cache===void 0?null:o.cache??E.cache},policy:r,setPolicy:y=>{p.current!==a&&u(y)}}}function Is(e){const s=V(),{measured:n,tab:a,setTab:l,providerTable:o,nodeTable:c,error:r,reload:u,dialog:d,setDialog:p,problem:m,form:h,setForm:k,removing:b,dialogTitle:i,formValid:v,formReason:g,submit:x,pending:N,submitting:T,submitLabel:D,groupHelp:M,groupNameError:W,agentError:$,options:S,policy:B,setPolicy:L}=ks(e),G=t.jsxs(t.Fragment,{children:[t.jsx("p",{className:"rp-note",children:s("nodes.note")}),t.jsx(Te,{error:r,onRetry:u}),t.jsx(ts,{model:o}),t.jsx(rs,{model:c})]});return t.jsxs("div",{className:"rp-page",children:[n?t.jsx($n,{keepMounted:!0,label:s("nav.nodes"),value:a,onChange:l,items:[{id:"list",label:s("nodes.tab.list"),content:G},{id:"latency",label:s("nodes.tab.latency"),content:t.jsx(as,{})}]}):G,t.jsxs(Gn,{title:i,narrow:!0,isOpen:d!==null&&!b,reason:N?null:g,onOpenChange:w=>{w||p(null)},footer:w=>t.jsxs(t.Fragment,{children:[t.jsx(F,{onPress:w,children:s("ui.cancel")}),t.jsx(F,{accent:!0,isDisabled:!v||T,isPending:N,onPress:()=>void x(w),children:D})]}),children:[m&&t.jsx(An,{takeFocus:!0,children:m.text},m.id),d?.kind==="provider"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:s("nodes.addProviderHelp")}),t.jsx(Q,{isDisabled:N,label:s("nodes.name"),value:h.name,placeholder:"sub-a",onChange:w=>k({...h,name:w})}),t.jsx(Q,{isDisabled:N,label:s("nodes.url"),value:h.value,placeholder:"https://example.org/sub?token=…",onChange:w=>k({...h,value:w})}),S?.intervals&&t.jsx(me,{label:s("nodes.interval"),items:S.intervals,value:S.interval,isDisabled:N,onChange:w=>k({...h,interval:w})}),S?.agent!==void 0&&t.jsx(Q,{isDisabled:N,label:s("nodes.agent"),value:h.agent,placeholder:S.agent,error:$??void 0,spellCheck:!1,onChange:w=>k({...h,agent:w})}),S?.cache!=null&&t.jsxs(t.Fragment,{children:[t.jsx(Fn,{isSelected:S.cache,isDisabled:N,onChange:w=>k({...h,cache:w}),children:s("nodes.cache")}),t.jsx("span",{className:"rp-label",children:s("nodes.cacheHelp")})]})]}),d?.kind==="group"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:M}),t.jsx(Q,{isDisabled:N,label:s("nodes.name"),value:h.name,placeholder:"hk",spellCheck:!1,description:s("arrange.groupNameHint"),error:W??void 0,onChange:w=>k({...h,name:w})}),t.jsx(Kn,{value:B,onChange:L,isDisabled:N})]}),d?.kind==="node"&&t.jsxs("div",{className:"rp-list",children:[t.jsx("span",{className:"rp-label",children:s("nodes.addNodeHelp")}),t.jsx(Q,{isDisabled:N,label:s("nodes.name"),value:h.name,placeholder:"hk-03",onChange:w=>k({...h,name:w})}),t.jsx(Q,{isDisabled:N,label:s("nodes.link"),value:h.value,placeholder:"vless://…",onChange:w=>k({...h,value:w})})]})]}),t.jsx(Wn,{title:i,isOpen:b,onCancel:()=>p(null),confirmLabel:D,isPending:N,isDisabled:T,error:m,onConfirm:()=>void x(()=>p(null)),children:t.jsx("p",{className:"rp-label",children:s(d?.kind==="removeProvider"?"nodes.removeProviderHelp":"nodes.removeNodeHelp")})})]})}export{Is as Nodes};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Overview-D7zbQze3.js b/luci-app-honk/root/etc/honk/dashboard/assets/Overview-D7zbQze3.js
deleted file mode 100644
index d2a9a5806..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Overview-D7zbQze3.js
+++ /dev/null
@@ -1 +0,0 @@
-import{r as E,j as t}from"./vendor-react-Bf71BWbF.js";import{ad as W,ae as C,af as H,ag as m,ah as N,W as g,ai as M,aj as $,V as P,ak as q,al as I,am as K,u as B,X as U,_ as z,$ as G,an as J,a1 as S,ao as Q,ap as X,aq as Y,ar as Z,as as ee,E as y,at as x,au as j,av as F,aw as ae,ax as w,ay as te,a8 as _,az as re,aA as se,b as D}from"./index-zQjLFfuj.js";import{d as oe,e as ne}from"./files-BxEOxSF8.js";import{D as ie,t as O}from"./Table-DLlwyNFJ.js";import{A as ce}from"./ActionGroup-C-LVMOvQ.js";import"./useGridSelectionCheckbox-BK6qtlfZ.js";import"./Virtualizer-CTh266-x.js";import"./ListLayout-DU_9AgrU.js";const T={ebpf:"ov.v.ebpf",userspace:"ov.v.userspace",mock:"ov.v.mock",active:"ov.v.active",degraded:"ov.v.degraded",detached:"ov.v.detached",failed:"ov.v.failed",disabled:"ov.v.disabled",full:"ov.v.full",partial:"ov.v.partial",none:"ov.v.none",real:"ov.v.real",loaded:"ov.v.loaded",not_loaded:"ov.v.notLoaded",attached:"ov.v.attached",partially_attached:"ov.v.partiallyAttached",published:"ov.v.published",not_published:"ov.v.notPublished",healthy:"ov.v.healthy",ready:"ov.v.ready",error:"ov.v.error",unknown:"ov.v.unknown",ingress:"ov.v.ingress",egress:"ov.v.egress"};function R(s,e){return T[s]?e(T[s]):s}function le(s,e,a,r){const i=s.ebpf,o=i?.maps?.conn_state,n=l=>R(l,a);return[[a("ov.f.kind"),n(s.kind)],[a("ov.f.state"),n(s.state)],[a("ov.f.visibility"),n(s.visibility)],...i?[[a("ov.f.backend"),n(i.backend)],[a("ov.f.programs"),n(i.programs)],[a("ov.f.hooks"),n(i.hooks)],[a("ov.f.routing"),n(i.routing.state)],[a("ov.f.health"),n(i.health)],[a("ov.f.maps"),n(i.maps?.state??"unknown")],[a("ov.f.connState"),o?.occupancy_known&&o.occupancy!==null?a("ui.fraction",{part:g(o.occupancy,r),whole:g(o.capacity,r)}):e]]:[]]}const de={service:"ov.v.cgroupService",shared:"ov.v.cgroupShared",unknown:"ui.unknown"};function ue(s,e,a,r=[]){const i=n=>{const l=I(n??null);return l===null?"—":g(l,a)};return[["ov.f.rss",m(s.process?.rss_bytes??null,a)],["ov.f.cgroupCurrent",m(s.cgroup?.current_bytes??null,a)],["ov.f.cgroupLimit",m(s.cgroup?.limit_bytes??null,a)],["ov.f.cgroupScope",s.cgroup?e(de[s.cgroup.scope]):"—"],["ov.f.oomHigh",i(s.cgroup?.events?.high)],["ov.f.oom",i(s.cgroup?.events?.oom)],["ov.f.oomKill",i(s.cgroup?.events?.oom_kill)],["ov.f.ebpfBytes",m(s.kernel?.ebpf_bytes??null,a)]].filter(([n])=>!r.includes(n)).map(([n,l])=>[e(n),l])}const V={connections:"nav.connections",flows:"rule.flows",routing_trace:"ov.r.routingTrace",dns_query:"ov.r.dnsQuery",dns_cache:"ov.r.dnsCache",events:"nav.events",probes:"ov.r.probes",traffic_history:"ov.r.trafficHistory",memory_history:"ov.r.memoryHistory",runtime_outbounds:"ov.r.outbounds",logs:"nav.logs",providers:"nodes.providers",config:"nav.config",runtime_settings:"settings.runtime",geodata:"settings.geodata"};function pe(s,e,a,r){const{capabilities:i,runtime:o,version:n,memory:l,datapath:d}=s,f=o?.lifecycle.state,v=o?.generation.config_revision??o?.generation.active_id??"—",u=o?.last_reload,k=o?.process.cpu_percent,h=W(l?.cgroup?.current_bytes??null,l?.cgroup?.limit_bytes??null),A=c=>c===null?"—":g(c,a),b=(c,p)=>c?"ready":p?"loading":"unavailable";return{status:{tone:q(f),text:f?P(K,f,r):r(e.capabilities||e.runtime?"ov.loading":"ov.unknown")},strip:[[r("ov.config"),M(v),v],[r("ov.uptime"),$(o?.lifecycle.uptime_seconds??null,a)],[r("ov.cpu"),k==null?"—":r("ui.percent",{n:g(k,a,1)})],[r("ov.lastReload"),u?N(u.finished_at,a):"—"]],reload:u?{tooltip:u.operation_id,tone:u.status==="succeeded"?"ok":u.status==="failed"?"err":"warn",text:r(u.status==="succeeded"?"ov.succeeded":u.status==="failed"?"ov.failed":"ov.running")}:null,engine:{state:b(!!n,e.version),fields:n?[[r("ov.f.engine"),n.engine.name+" "+n.engine.version],[r("ov.f.api"),r("ui.apiVersion",{name:n.api.name,major:n.api.major,status:n.api.status})],[r("ov.f.build"),[n.build?.revision,n.build?.target].filter(Boolean).join(r("ui.separator"))||"—"],[r("ov.f.instance"),o?.instance_id??"—"],[r("ov.f.started"),N(o?.lifecycle.started_at??null,a)],[r("ov.f.activated"),N(o?.generation.activated_at??null,a)]]:[],profiles:i?.profiles.map(c=>({id:c,text:r(c==="base"?"ov.profileBase":"ov.profileFull")}))??[]},counters:{state:b(!!o,e.capabilities||e.runtime),fields:o?[[r("ov.f.tcp"),A(o.traffic.connections.tcp)],[r("ov.f.udp"),A(o.traffic.connections.udp)],[r("ov.f.total"),A(o.traffic.connections.total)],[r("ui.upload"),m(o.traffic.bytes.upload,a)],[r("ui.download"),m(o.traffic.bytes.download,a)],[r("ov.f.rateWindow"),o.traffic.rates?r("ui.seconds",{n:g(o.traffic.rates.window_seconds,a,1)}):"—"]]:[],since:o?r("ov.countersSince",{t:N(o.traffic.counter_since,a),scope:r(o.traffic.scope==="visible"?"ov.scopeVisible":"ov.scopeAll")}):""},memory:{state:b(!!l,e.capabilities||e.memory),fields:l?ue(l,r,a,h===null?[]:["ov.f.cgroupCurrent","ov.f.cgroupLimit"]):[],bar:h===null?null:{label:r("ov.f.cgroupPercent"),value:r("ui.fraction",{part:m(l?.cgroup?.current_bytes??null,a),whole:m(l?.cgroup?.limit_bytes??null,a)}),pct:h,tone:H(h)}},datapath:{state:b(!!d,e.capabilities||e.datapath),fields:d?le(d,r("ov.unknown"),r,a):[],showAttachments:!!d?.ebpf,attachments:(d?.ebpf?.attachments??[]).map((c,p)=>({id:String(p),name:c.name,interface:c.interface,direction:R(c.direction,r),state:R(c.state,r)})),errors:d?.errors.map(c=>({tooltip:c.code,text:C(c.code,c.message,r)}))??[],warning:d?.ebpf?.last_error&&!d.errors.some(c=>c.message===d.ebpf?.last_error)?r("ui.backendMessage",{message:d.ebpf.last_error}):null},resources:{state:b(!!i,e.capabilities),rows:i?Object.keys(V).map(c=>{const p=i.resources[c].available!==!1;return{id:c,label:r(V[c]),tone:p?"ok":"muted",text:r(p?"ov.available":"ov.notAvailable"),dotOnly:p}}).sort((c,p)=>+(c.tone==="muted")-+(p.tone==="muted")):[]},canExport:!!o}}function ve(s,e){return JSON.stringify({exported_at:e,...s},null,2)}function me(){const s=B(),e=U[z()],a=G(),r=a.data?.resources,i=J(S(r,"runtime",{whileLoading:!1})),o=Q(S(r,"datapath",{whileLoading:!1})),n=X(S(r,"runtime_memory",{whileLoading:!1})),l=Y(),d=Z(i.data,a.data,i.refetch),f=E.useMemo(()=>({capabilities:a.data,runtime:i.data,version:l.data,memory:n.data,datapath:o.data}),[a.data,i.data,l.data,n.data,o.data]),v=E.useMemo(()=>pe(f,{capabilities:a.loading,runtime:i.loading,version:l.loading,memory:n.loading,datapath:o.loading},e,s),[f,a.loading,i.loading,l.loading,n.loading,o.loading,e,s]),u=ee(),k={err:u.love,warn:u.gold,ok:u.cat[0]},h={...v.memory,bar:v.memory.bar?{...v.memory.bar,color:k[v.memory.bar.tone]}:null};return{...v,memory:h,errors:{capabilities:a.error,runtime:i.error,version:l.error,memory:n.error,datapath:o.error},retry:{capabilities:a.refetch,runtime:i.refetch,version:l.refetch,memory:n.refetch,datapath:o.refetch},actions:d.actions,export:()=>oe(ne("doona-state","json"),ve(f,new Date().toISOString()),"application/json")}}function L({cells:s,extra:e=0}){return t.jsxs("div",{className:"rp-body-wait",children:[t.jsx("div",{className:"rp-kv","aria-hidden":"true",children:Array.from({length:s},(a,r)=>t.jsxs("div",{children:[t.jsx("span",{className:"k",children:" "}),t.jsx("span",{className:"v",children:" "})]},r))}),e>0&&t.jsx("div",{"aria-hidden":"true",style:{height:e}}),t.jsx(D,{})]})}const fe=2+O.headingHeight+2*O.rowHeight;function ke(){const s=B(),e=me();return t.jsxs("div",{className:"rp-page",children:[t.jsx(y,{error:e.errors.capabilities,onRetry:e.retry.capabilities}),t.jsxs("div",{className:"rp-between",children:[t.jsxs("div",{className:"rp-cluster",children:[t.jsx(x,{tone:e.status.tone,children:e.status.text}),t.jsx(j,{row:!0,items:e.strip}),e.reload&&t.jsx(F,{text:e.reload.tooltip,children:t.jsx(x,{small:!0,tone:e.reload.tone,children:e.reload.text})})]}),t.jsx("div",{className:"rp-cluster",children:t.jsx(ce,{actions:[{id:"export",label:s("ov.export"),icon:t.jsx(ae,{}),isDisabled:!e.canExport,onAction:e.export},...e.actions]})})]}),t.jsxs("div",{className:"rp-g3",children:[t.jsxs(w,{title:s("ov.engine"),children:[t.jsx(y,{error:e.errors.version,onRetry:e.retry.version}),e.engine.state==="ready"?t.jsxs(t.Fragment,{children:[t.jsx(j,{items:e.engine.fields}),e.engine.profiles.length>0&&t.jsx("div",{className:"rp-cluster",children:e.engine.profiles.map(a=>t.jsx(te,{children:a.text},a.id))})]}):e.engine.state==="loading"?t.jsx(L,{cells:6,extra:e.engine.profiles.length>0?20:0}):e.errors.version?null:t.jsx(_,{children:s("ov.unavailable")})]}),t.jsxs(w,{title:s("ov.counters"),children:[t.jsx(y,{error:e.errors.runtime,onRetry:e.retry.runtime}),e.counters.state==="ready"?t.jsxs(t.Fragment,{children:[t.jsx(j,{items:e.counters.fields}),t.jsx("span",{className:"rp-label",children:e.counters.since})]}):e.counters.state==="loading"?t.jsx(L,{cells:6,extra:16}):e.errors.runtime?null:t.jsx(_,{children:s("ov.unavailable")})]}),t.jsxs(w,{title:s("ov.memory"),children:[t.jsx(y,{error:e.errors.memory,onRetry:e.retry.memory}),e.memory.state==="ready"?t.jsxs(t.Fragment,{children:[e.memory.bar&&t.jsx(re,{label:e.memory.bar.label,value:e.memory.bar.value,pct:e.memory.bar.pct,color:e.memory.bar.color}),t.jsx(j,{items:e.memory.fields})]}):e.memory.state==="loading"?t.jsx(L,{cells:8}):e.errors.memory?null:t.jsx(_,{children:s("ov.unavailable")})]})]}),t.jsxs("div",{className:"rp-g21 rp-overview-lower",children:[t.jsxs(w,{title:s("ov.datapath"),children:[t.jsx(y,{error:e.errors.datapath,onRetry:e.retry.datapath}),e.datapath.state==="ready"?t.jsxs(t.Fragment,{children:[t.jsx(j,{items:e.datapath.fields}),e.datapath.showAttachments&&t.jsx(ie,{label:s("ov.attachments"),height:250,rows:e.datapath.attachments,empty:s("ov.unknown"),cols:[{id:"n",label:s("ov.name"),minWidth:128,isRowHeader:!0,render:a=>a.name},{id:"i",label:s("ov.interface"),minWidth:88,drop:2,render:a=>a.interface},{id:"d",label:s("ov.direction"),minWidth:80,grow:0,drop:1,render:a=>a.direction},{id:"s",label:s("ov.state"),minWidth:88,grow:0,render:a=>a.state}]}),(e.datapath.errors.length>0||e.datapath.warning)&&t.jsxs("div",{className:"rp-cluster",children:[e.datapath.errors.map((a,r)=>t.jsx(F,{text:a.tooltip,children:t.jsx(x,{small:!0,tone:"err",children:a.text})},r)),e.datapath.warning&&t.jsx(x,{small:!0,tone:"warn",children:e.datapath.warning})]})]}):e.datapath.state==="loading"?t.jsx(L,{cells:10,extra:fe}):e.errors.datapath?null:t.jsx(_,{children:s("ov.unavailable")})]}),t.jsx(w,{title:s("ov.resources"),children:e.resources.state==="ready"?t.jsx("div",{className:"rp-capabilities",children:e.resources.rows.map(a=>t.jsxs("div",{className:"rp-capability"+(a.tone==="muted"?" unavailable":""),children:[t.jsx(x,{tone:a.tone,children:a.label}),a.dotOnly?t.jsx(se,{children:a.text}):t.jsx("span",{className:"rp-capability-status",children:a.text})]},a.id))}):e.resources.state==="loading"?t.jsx(D,{}):e.errors.capabilities?null:t.jsx(_,{children:s("ov.unavailable")})})]})]})}export{ke as Overview};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Overview-Fg9wiBtP.js b/luci-app-honk/root/etc/honk/dashboard/assets/Overview-Fg9wiBtP.js
new file mode 100644
index 000000000..afad9019e
--- /dev/null
+++ b/luci-app-honk/root/etc/honk/dashboard/assets/Overview-Fg9wiBtP.js
@@ -0,0 +1 @@
+import{r as S,j as a}from"./vendor-react-Bf71BWbF.js";import{ak as T,al as R,am as U,an as K,ao as $,ap as h,aq as B,a1 as b,ar as G,as as J,at as q,au as z,u as W,a as Q,a5 as X,av as Y,a7 as A,aw as Z,ax as ee,ay as ae,az as te,aA as se,a2 as re,aB as oe,aC as _,E as L,L as M,aD as N,aE as C,aF as ie,aG as y,aH as ne,af as H,aI as le,aJ as ce,j as O,aK as de,B as pe,aL as ue}from"./index-CXHBmSa5.js";import{d as ve,e as me}from"./files-BxEOxSF8.js";import{D as he,t as I}from"./Table-D0NFHHNQ.js";import{A as fe}from"./ActionGroup-90AzAQje.js";import{D as xe}from"./DaeCode-STEiRZuV.js";import"./useGridSelectionCheckbox-BV96yL-N.js";import"./Virtualizer--Vfl8O3n.js";import"./ListLayout-CPapuywx.js";const V={ebpf:"ov.v.ebpf",userspace:"ov.v.userspace",mock:"ov.v.mock",active:"ov.v.active",degraded:"ov.v.degraded",detached:"ov.v.detached",failed:"ov.v.failed",disabled:"ov.v.disabled",full:"ov.v.full",partial:"ov.v.partial",none:"ov.v.none",real:"ov.v.real",loaded:"ov.v.loaded",not_loaded:"ov.v.notLoaded",attached:"ov.v.attached",partially_attached:"ov.v.partiallyAttached",published:"ov.v.published",not_published:"ov.v.notPublished",healthy:"ov.v.healthy",ready:"ov.v.ready",error:"ov.v.error",unknown:"ov.v.unknown",ingress:"ov.v.ingress",egress:"ov.v.egress"};function E(o,s){return V[o]?s(V[o]):o}function ge(o,s,e){if(o==="degraded")return{title:e("ov.v.degraded"),text:e(s?"ov.degradedHelp.runtime":"ov.degradedHelp.datapath")};if(o==="unknown")return{title:e("ov.v.unknown"),text:e("ov.unknownHelp")}}function be(o,s,e,t,r=!1){const i=o.ebpf,l=i?.maps?.conn_state,n=(c,p)=>{const f=ge(p,r,e);return f?{label:e(c),value:E(p,e),help:f}:[e(c),E(p,e)]};return[n("ov.f.kind",o.kind),n("ov.f.state",o.state),n("ov.f.visibility",o.visibility),...i?[n("ov.f.backend",i.backend),n("ov.f.programs",i.programs),n("ov.f.hooks",i.hooks),n("ov.f.routing",i.routing.state),n("ov.f.health",i.health),n("ov.f.maps",i.maps?.state??"unknown"),[e("ov.f.connState"),l?.occupancy_known&&l.occupancy!==null?e("ui.fraction",{part:b(l.occupancy,t),whole:b(l.capacity,t)}):l?e("ov.occupancyUnknown",{capacity:b(l.capacity,t)}):s]]:[]]}const je={service:"ov.v.cgroupService",shared:"ov.v.cgroupShared",unknown:"ui.unknown"},ye={service:"ov.cgroupHelp.service",shared:"ov.cgroupHelp.shared",unknown:"ov.cgroupHelp.unknown"};function we(o,s,e,t=[]){const r=n=>{const c=z(n??null);return c===null?"—":b(c,e)},i=[["ov.f.rss",h(o.process?.rss_bytes??null,e)],["ov.f.cgroupCurrent",h(o.cgroup?.current_bytes??null,e)],["ov.f.cgroupLimit",h(o.cgroup?.limit_bytes??null,e)],["ov.f.cgroupScope",o.cgroup?s(je[o.cgroup.scope]):"—"],["ov.f.oomHigh",r(o.cgroup?.events?.high)],["ov.f.oom",r(o.cgroup?.events?.oom)],["ov.f.oomKill",r(o.cgroup?.events?.oom_kill)],["ov.f.ebpfBytes",h(o.kernel?.ebpf_bytes??null,e)]],l=o.cgroup?.scope;return i.filter(([n])=>!t.includes(n)).map(([n,c])=>n==="ov.f.cgroupScope"&&l?{label:s(n),value:c,help:{title:s(n),text:s("ui.valuePair",{label:c,value:s(ye[l])})}}:[s(n),c])}function ke(o,s,e,t){const{capabilities:r,runtime:i,version:l,memory:n,datapath:c,limits:p=[]}=o,f=i?.lifecycle.state,j=i?.generation.config_revision??i?.generation.active_id??"—",u=i?.last_reload,w=i?.process.cpu_percent,x=T(n?.cgroup?.current_bytes??null,n?.cgroup?.limit_bytes??null),v=d=>d===null?"—":b(d,e),m=(d,g)=>d?"ready":g?"loading":"unavailable";return{status:q(f,c?.state,t(s.capabilities||s.runtime?"ov.loading":"ov.unknown"),t),strip:[{label:t("ov.config"),value:G(j),full:j,help:{title:t("ov.config"),text:t("ov.configHelp")}},[t("ov.uptime"),J(i?.lifecycle.uptime_seconds??null,e)],[t("ov.cpu"),w==null?"—":t("ui.percent",{n:b(w,e,1)})],[t("ov.lastReload"),u?B(u.finished_at,e):"—"]],reload:u?{tooltip:u.operation_id,tone:u.status==="succeeded"?"ok":u.status==="failed"?"err":"warn",text:t(u.status==="succeeded"?"ov.succeeded":u.status==="failed"?"ov.failed":"ov.running")}:null,engine:{state:m(!!l,s.version),fields:l?[[t("ov.f.engine"),l.engine.name+" "+l.engine.version],[t("ov.f.api"),t("ui.apiVersion",{name:l.api.name,major:l.api.major,status:l.api.status})],[t("ov.f.build"),[l.build?.revision,l.build?.target].filter(Boolean).join(t("ui.separator"))||"—"],[t("ov.f.instance"),i?.instance_id??"—"],[t("ov.f.started"),B(i?.lifecycle.started_at??null,e)],[t("ov.f.activated"),B(i?.generation.activated_at??null,e)]]:[],profiles:r?.profiles.map(d=>({id:d,text:t(d==="base"?"ov.profileBase":"ov.profileFull")}))??[]},counters:{state:m(!!i,s.capabilities||s.runtime),fields:i?[[t("ov.f.tcp"),v(i.traffic.connections.tcp)],[t("ov.f.udp"),v(i.traffic.connections.udp)],[t("ov.f.total"),v(i.traffic.connections.total)],[t("ui.upload"),h(i.traffic.bytes.upload,e)],[t("ui.download"),h(i.traffic.bytes.download,e)],{label:t("ov.f.rateWindow"),value:i.traffic.rates?t("ui.seconds",{n:b(i.traffic.rates.window_seconds,e,1)}):"—",help:{title:t("ov.f.rateWindow"),text:t("ov.rateWindowHelp")}}]:[],since:i?t("ov.countersSince",{t:B(i.traffic.counter_since,e),scope:t(i.traffic.scope==="visible"?"ov.scopeVisible":"ov.scopeAll")}):""},memory:{state:m(!!n,s.capabilities||s.memory),fields:n?we(n,t,e,x===null?[]:["ov.f.cgroupCurrent","ov.f.cgroupLimit"]):[],bar:x===null?null:{label:t("ov.f.cgroupPercent"),value:t("ui.fraction",{part:h(n?.cgroup?.current_bytes??null,e),whole:h(n?.cgroup?.limit_bytes??null,e)}),pct:x,tone:$(x)}},datapath:{state:m(!!c,s.capabilities||s.datapath),fields:c?be(c,t("ov.unknown"),t,e,f==="degraded"):[],showAttachments:!!c?.ebpf,attachments:(c?.ebpf?.attachments??[]).map((d,g)=>({id:String(g),name:d.name,interface:d.interface,direction:E(d.direction,t),state:E(d.state,t)})),errors:c?.errors.map(d=>({tooltip:d.code,text:U(K(d.code,d.message,t),t)}))??[],warning:c?.ebpf?.last_error&&!c.errors.some(d=>d.message===c.ebpf?.last_error)?t("ui.backendMessage",{message:c.ebpf.last_error}):null},resources:{state:m(!!r,s.capabilities),rows:r?Object.keys(R).filter(d=>!p.some(g=>g.items.some(k=>k.id===d))).map(d=>({id:d,label:t(R[d]),text:t("ov.available")})):[]},limits:p,canExport:!!i}}function _e(o,s){return JSON.stringify({exported_at:s,...o},null,2)}const F={limits:"overview-limits",datapath:"overview-datapath"};function Le(o=""){const s=W(),e=Q(),t=re[e],r=X(),i=r.data?.resources,l=Y(A(i,"runtime",{whileLoading:!1})),n=Z(A(i,"datapath",{whileLoading:!1})),c=ee(A(i,"runtime_memory",{whileLoading:!1})),p=ae(),f=te(l.data,r.data,l.refetch),j=S.useMemo(()=>({capabilities:r.data,runtime:l.data,version:p.data,memory:c.data,datapath:n.data}),[r.data,l.data,p.data,c.data,n.data]),u=S.useMemo(()=>r.data?se(r.data,p.data,s,e):[],[r.data,p.data,s,e]),w=u.length>0,x=!!n.data;S.useEffect(()=>{const k=new URLSearchParams(o).get("card");(k==="limits"&&w||k==="datapath"&&x)&&document.getElementById(F[k])?.scrollIntoView({block:"start"})},[o,w,x]);const v=S.useMemo(()=>ke({...j,limits:u},{capabilities:r.loading,runtime:l.loading,version:p.loading,memory:c.loading,datapath:n.loading},t,s),[j,u,r.loading,l.loading,p.loading,c.loading,n.loading,t,s]),m=oe(),d={err:m.love,warn:m.gold,ok:m.cat[0]},g={...v.memory,bar:v.memory.bar?{...v.memory.bar,color:d[v.memory.bar.tone]}:null};return{...v,memory:g,errors:{capabilities:r.error,runtime:l.error,version:p.error,memory:c.error,datapath:n.error},retry:{capabilities:r.refetch,runtime:l.refetch,version:p.refetch,memory:c.refetch,datapath:n.refetch},actions:f.actions,export:()=>ve(me("doona-state","json"),_e(j,new Date().toISOString()),"application/json")}}function D({cells:o,extra:s=0}){return a.jsxs("div",{className:"rp-body-wait",children:[a.jsx("div",{className:"rp-kv","aria-hidden":"true",children:Array.from({length:o},(e,t)=>a.jsxs("div",{children:[a.jsx("span",{className:"k",children:" "}),a.jsx("span",{className:"v",children:" "})]},t))}),s>0&&a.jsx("div",{"aria-hidden":"true",style:{height:s}}),a.jsx(O,{})]})}function P({link:o}){return a.jsxs(M,{appearance:"link",external:o.external,href:o.href,children:[o.text,o.external&&a.jsx("span",{"aria-hidden":"true",children:"↗"})]})}function Ne({help:o}){return a.jsx(de,{title:o.label,placement:"bottom end",trigger:a.jsxs(pe,{quiet:!0,children:[a.jsx(ue,{}),o.label]}),children:()=>a.jsxs(a.Fragment,{children:[a.jsx("p",{className:"rp-limit-help",children:o.text}),o.snippet&&a.jsx(xe,{as:"pre",className:"rp-limit-snippet",text:o.snippet}),o.link&&a.jsx(P,{link:o.link})]})})}const He=2+I.headingHeight+2*I.rowHeight;function Ve({query:o}){const s=W(),e=Le(o),t=a.jsx(_,{tone:e.status.tone,children:e.status.text});return a.jsxs("div",{className:"rp-page",children:[a.jsx(L,{error:e.errors.capabilities,onRetry:e.retry.capabilities}),a.jsxs("div",{className:"rp-between",children:[a.jsxs("div",{className:"rp-cluster",children:[e.status.href?a.jsx(M,{appearance:"link",href:e.status.href,children:t}):t,a.jsx(N,{row:!0,items:e.strip}),e.reload&&a.jsx(C,{text:e.reload.tooltip,children:a.jsx(_,{small:!0,tone:e.reload.tone,children:e.reload.text})})]}),a.jsx("div",{className:"rp-cluster",children:a.jsx(fe,{actions:[{id:"export",label:s("ov.export"),icon:a.jsx(ie,{}),isDisabled:!e.canExport,onAction:e.export},...e.actions]})})]}),a.jsxs("div",{className:"rp-g3",children:[a.jsxs(y,{title:s("ov.engine"),children:[a.jsx(L,{error:e.errors.version,onRetry:e.retry.version}),e.engine.state==="ready"?a.jsxs(a.Fragment,{children:[a.jsx(N,{items:e.engine.fields}),e.engine.profiles.length>0&&a.jsx("div",{className:"rp-cluster",children:e.engine.profiles.map(r=>a.jsx(ne,{children:r.text},r.id))})]}):e.engine.state==="loading"?a.jsx(D,{cells:6,extra:e.engine.profiles.length>0?20:0}):e.errors.version?null:a.jsx(H,{children:s("ov.unavailable")})]}),a.jsxs(y,{title:s("ov.counters"),children:[a.jsx(L,{error:e.errors.runtime,onRetry:e.retry.runtime}),e.counters.state==="ready"?a.jsxs(a.Fragment,{children:[a.jsx(N,{items:e.counters.fields}),a.jsx("span",{className:"rp-label",children:e.counters.since})]}):e.counters.state==="loading"?a.jsx(D,{cells:6,extra:16}):e.errors.runtime?null:a.jsx(H,{children:s("ov.unavailable")})]}),a.jsxs(y,{title:s("ov.memory"),children:[a.jsx(L,{error:e.errors.memory,onRetry:e.retry.memory}),e.memory.state==="ready"?a.jsxs(a.Fragment,{children:[e.memory.bar&&a.jsx(le,{label:e.memory.bar.label,value:e.memory.bar.value,pct:e.memory.bar.pct,color:e.memory.bar.color}),a.jsx(N,{items:e.memory.fields})]}):e.memory.state==="loading"?a.jsx(D,{cells:8}):e.errors.memory?null:a.jsx(H,{children:s("ov.unavailable")})]})]}),a.jsxs("div",{className:"rp-g21 rp-overview-lower",children:[a.jsxs(y,{title:s("ov.datapath"),titleId:F.datapath,help:{title:s("ov.datapath"),text:s("ov.datapathHelp")},children:[a.jsx(L,{error:e.errors.datapath,onRetry:e.retry.datapath}),e.datapath.state==="ready"?a.jsxs(a.Fragment,{children:[a.jsx(N,{items:e.datapath.fields}),e.datapath.showAttachments&&a.jsx(he,{label:s("ov.attachments"),height:250,rows:e.datapath.attachments,empty:s("ov.noAttachments"),cols:[{id:"n",label:s("ov.name"),minWidth:128,isRowHeader:!0,render:r=>r.name},{id:"i",label:s("ov.interface"),minWidth:88,drop:2,render:r=>r.interface},{id:"d",label:s("ov.direction"),minWidth:80,grow:0,drop:1,render:r=>r.direction},{id:"s",label:s("ov.state"),minWidth:88,grow:0,render:r=>r.state}]}),(e.datapath.errors.length>0||e.datapath.warning)&&a.jsxs("div",{className:"rp-cluster",children:[e.datapath.errors.map((r,i)=>a.jsx(C,{text:r.tooltip,children:a.jsx(_,{small:!0,tone:"err",children:r.text})},i)),e.datapath.warning&&a.jsx(_,{small:!0,tone:"warn",children:e.datapath.warning})]})]}):e.datapath.state==="loading"?a.jsx(D,{cells:10,extra:He}):e.errors.datapath?null:a.jsx(H,{children:s("ov.unavailable")})]}),a.jsx(y,{title:s("ov.resources"),children:e.resources.state==="ready"?a.jsx("div",{className:"rp-capabilities",children:e.resources.rows.map(r=>a.jsxs("div",{className:"rp-capability",children:[a.jsx(_,{tone:"ok",children:r.label}),a.jsx(ce,{children:r.text})]},r.id))}):e.resources.state==="loading"?a.jsx(O,{}):e.errors.capabilities?null:a.jsx(H,{children:s("ov.unavailable")})})]}),e.limits.length>0&&a.jsx(y,{title:s("ov.lim.title"),titleId:F.limits,children:a.jsx("ul",{className:"rp-limits",children:e.limits.map(r=>a.jsxs("li",{className:"rp-limit",children:[a.jsxs("div",{className:"rp-limit-text",children:[a.jsx("span",{children:r.headline}),r.features&&a.jsx("span",{className:"rp-note",children:r.features})]}),r.help?a.jsx(Ne,{help:r.help}):r.link&&a.jsx(P,{link:r.link})]},r.cause))})})]})}export{Ve as Overview};
diff --git a/luci-app-honk/root/etc/honk/dashboard/assets/Policies-VixfIaVZ.js b/luci-app-honk/root/etc/honk/dashboard/assets/Policies-VixfIaVZ.js
deleted file mode 100644
index 82bb953c3..000000000
--- a/luci-app-honk/root/etc/honk/dashboard/assets/Policies-VixfIaVZ.js
+++ /dev/null
@@ -1,2 +0,0 @@
-const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Arrange-C-Cvg5Lz.js","./vendor-react-Bf71BWbF.js","./index-zQjLFfuj.js","./index-CszNs-yj.css","./Virtualizer-CTh266-x.js","./ListLayout-DU_9AgrU.js","./DaeCode-B4MDdwFy.js","./policyText-IIH31itq.js","./PolicyPicker-iyQz7WhP.js","./useFilter-BYneYrGs.js","./useGridSelectionCheckbox-BK6qtlfZ.js","./Arrange-Dd3j3leY.css"])))=>i.map(i=>d[i]);
-import{bp as Ye,bq as Qe,br as Je,bs as pe,bt as te,bu as we,bv as Ze,bw as et,bx as tt,by as rt,bz as De,bA as ie,bB as oe,bC as me,bD as G,bE as q,bF as X,bG as ee,bH as at,bI as ne,bJ as Ae,bK as it,bL as ot,bM as Re,bN as nt,bO as de,bP as fe,bQ as Ke,bR as ue,bS as lt,bT as xe,bU as Pe,bV as he,bW as be,bX as Fe,bY as st,bZ as ct,b_ as dt,b$ as He,c0 as ut,c1 as pt,c2 as le,c3 as ft,c4 as ht,c5 as bt,c6 as mt,c7 as gt,c8 as yt,c9 as vt,ca as xt,cb as $t,cc as kt,cd as wt,ce as Pt,a as ce,cf as It,V as St,aU as Oe,cg as Dt,aI as Et,y as Mt,ch as jt,aE as Ct,W as Nt,u as V,X as Tt,_ as _t,a8 as $e,ci as Lt,cj as ge,bd as ye,T as Ie,b9 as zt,ck as At,cl as Be,M as Ve,I as Rt,B as A,a7 as Kt,aV as Ft,$ as Ht,a3 as Ot,a1 as Ee,a2 as Bt,cm as Vt,cn as Gt,z as Ut,b4 as Wt,b5 as qt,bi as Xt,co as Ge,G as Yt,b0 as U,cp as Qt,cq as Jt,cr as Zt,E as Ue,b as Me,cs as er,bc as tr,ax as rr,ct as ar,cu as ir,ay as or,at as se,bo as nr,cv as lr,au as sr,aS as cr}from"./index-zQjLFfuj.js";import{r as b,$ as P,j as n}from"./vendor-react-Bf71BWbF.js";import{$ as dr,a as ur,b as pr,c as fr,d as hr}from"./useGridSelectionCheckbox-BK6qtlfZ.js";import{$ as br,a as B,b as ve,c as Q,d as mr}from"./Virtualizer-CTh266-x.js";import{$ as gr}from"./useFilter-BYneYrGs.js";import{g as yr,a as vr}from"./policyText-IIH31itq.js";import{P as xr}from"./PolicyPicker-iyQz7WhP.js";const Se=new WeakMap;function ke(a,t){let{id:e}=Se.get(a)??{};if(!e)throw new Error("Unknown list");return`${e}-${$r(t)}`}function $r(a){return typeof a=="string"?a.replace(/\s*/g,""):""+a}function kr(a,t,e){let{isVirtualized:r,keyboardDelegate:i,layoutDelegate:l,onAction:s,disallowTypeAhead:d,linkBehavior:o="action",keyboardNavigationBehavior:c="arrow",escapeKeyBehavior:p="clearSelection",shouldSelectOnPressUp:m}=a;!a["aria-label"]&&!a["aria-labelledby"]&&console.warn("An aria-label or aria-labelledby prop is required for accessibility.");let{listProps:v}=Ye({selectionManager:t.selectionManager,collection:t.collection,disabledKeys:t.disabledKeys,ref:e,keyboardDelegate:i,layoutDelegate:l,isVirtualized:r,selectOnFocus:t.selectionManager.selectionBehavior==="replace",shouldFocusWrap:a.shouldFocusWrap,linkBehavior:o,disallowTypeAhead:d,autoFocus:a.autoFocus,escapeKeyBehavior:p,UNSTABLE_focusOnEntry:a.UNSTABLE_focusOnEntry}),h=Qe(a.id);Se.set(t,{id:h,onAction:s,linkBehavior:o,keyboardNavigationBehavior:c,shouldSelectOnPressUp:m});let f=dr({selectionManager:t.selectionManager,hasItemActions:!!s}),x=Je(e,{isDisabled:t.collection.size!==0}),g=pe(a,{labelable:!0}),k=te(g,{role:"grid",id:h,"aria-multiselectable":t.selectionManager.selectionMode==="multiple"?"true":void 0},t.collection.size===0?{tabIndex:x?-1:0}:v,f);return r&&(k["aria-rowcount"]=t.collection.size,k["aria-colcount"]=1),ur({},t),{gridProps:k}}const je={expand:{ltr:"ArrowRight",rtl:"ArrowLeft"},collapse:{ltr:"ArrowLeft",rtl:"ArrowRight"}};function wr(a,t,e){let{node:r,isVirtualized:i,focusMode:l="row",allowsArrowNavigation:s}=a,{direction:d}=we(),{onAction:o,linkBehavior:c,keyboardNavigationBehavior:p,shouldSelectOnPressUp:m}=Se.get(t),v=Ze(),h=b.useRef(null),f=()=>{if(e.current!==null){if(l==="child"){if(De(e.current)&&e.current!==ie(oe(e.current)))return;let I=me(e.current,{tabbable:!0}).firstChild();if(I){G(I),q(I,{containingElement:X(I)});return}}(h.current!=null&&r.key!==h.current||!De(e.current))&&G(e.current)}},x={},g=a.hasChildItems,k=t.selectionManager.isLink(r.key);if(r!=null&&"expandedKeys"in t){let u=t.collection.getChildren?.(r.key);g=g||[...u??[]].length>1,o==null&&!k&&t.selectionManager.selectionMode==="none"&&g&&(o=()=>t.toggleKey(r.key));let I=g?t.expandedKeys.has(r.key):void 0,w=1,D=r.index;if(r.level>=0&&r?.parentKey!=null){let E=t.collection.getItem(r.parentKey);if(E){let R=Pr(E,t.collection);w=[...R].filter(K=>K.type==="item").length,D>0&&R[0].type!=="item"&&(D-=1)}}else w=[...t.collection].filter(E=>E.level===0&&E.type==="item").length;x={"aria-expanded":I,"aria-level":r.level+1,"aria-posinset":D+1,"aria-setsize":w}}let{itemProps:j,...T}=et({selectionManager:t.selectionManager,key:r.key,ref:e,isVirtualized:i,shouldSelectOnPressUp:a.shouldSelectOnPressUp||m,onAction:o||r.props?.onAction?tt(r.props?.onAction,o?()=>o(r.key):void 0):void 0,focus:f,linkBehavior:c}),N=u=>{let I=ie(oe(e.current));if(!ne(u.currentTarget,ee(u))||!e.current||!I)return;let w=me(e.current);if(w.currentNode=I,!Ce(u,t,r,g,d,I,e.current,s))switch(u.key){case"ArrowLeft":if(p==="arrow"){let D=d==="rtl"?w.nextNode():w.previousNode();if(D)u.preventDefault(),u.stopPropagation(),G(D),q(D,{containingElement:X(e.current)});else if(u.preventDefault(),u.stopPropagation(),d==="rtl")G(e.current),q(e.current,{containingElement:X(e.current)});else{w.currentNode=e.current;let E=Ne(w);E&&(G(E),q(E,{containingElement:X(e.current)}))}}break;case"ArrowRight":if(p==="arrow"){let D=d==="rtl"?w.previousNode():w.nextNode();if(D)u.preventDefault(),u.stopPropagation(),G(D),q(D,{containingElement:X(e.current)});else if(u.preventDefault(),u.stopPropagation(),d==="ltr")G(e.current),q(e.current,{containingElement:X(e.current)});else{w.currentNode=e.current;let E=Ne(w);E&&(G(E),q(E,{containingElement:X(e.current)}))}}break;case"ArrowUp":case"ArrowDown":!u.altKey&&ne(e.current,ee(u))&&(u.stopPropagation(),u.preventDefault(),e.current.parentElement?.dispatchEvent(new KeyboardEvent(u.nativeEvent.type,u.nativeEvent)));break}},$=u=>{if(h.current=r.key,ee(u)!==e.current){at()||t.selectionManager.setFocusedKey(r.key);return}l==="child"&&u.relatedTarget&&ne(e.current,u.relatedTarget)||requestAnimationFrame(()=>{l==="child"&&ie(oe(e.current))===e.current&&f()})},y=u=>{let I=ie(oe(e.current));if(!(!ne(u.currentTarget,ee(u))||!e.current||!I)){if(p==="tab"){if(ee(u)!==e.current&&u.key!=="Tab"){u.stopPropagation();return}if(Ce(u,t,r,g,d,I,e.current,s))return}switch(u.key){case"Tab":if(p==="tab"){let w=me(e.current,{tabbable:!0});w.currentNode=I,(u.shiftKey?w.previousNode():w.nextNode())&&u.stopPropagation()}}}},S=rt(r.props),M=T.hasAction?S:{},_=te(j,M,{role:"row",onKeyDownCapture:p==="arrow"||s?N:void 0,onFocus:$,"aria-label":r["aria-label"]||r.textValue||void 0,"aria-selected":t.selectionManager.canSelectItem(r.key)?t.selectionManager.isSelected(r.key):void 0,"aria-disabled":t.selectionManager.isDisabled(r.key)||void 0,"aria-labelledby":v&&(r["aria-label"]||r.textValue)?`${ke(t,r.key)} ${v}`:void 0,id:ke(t,r.key)});l==="child"&&s&&p==="tab"&&(_.tabIndex=-1);let C=_.onKeyDown;if(_.onKeyDown=u=>{y(u),u.isPropagationStopped()||C?.(u)},i){let{collection:u}=t,I=[...u];_["aria-rowindex"]=I.find(w=>w.type==="section")?[...u.getKeys()].filter(w=>u.getItem(w)?.type!=="section").findIndex(w=>w===r.key)+1:r.index+1}let z={role:"gridcell","aria-colindex":1};return{rowProps:{...te(_,x)},gridCellProps:z,descriptionProps:{id:v},...T}}function Ce(a,t,e,r,i,l,s,d){if(!("expandedKeys"in t)||!d&&l!==s)return!1;if(a.key===je.expand[i]&&t.selectionManager.focusedKey===e.key&&r&&!t.expandedKeys.has(e.key))return t.toggleKey(e.key),a.stopPropagation(),!0;if(a.key===je.collapse[i]&&t.selectionManager.focusedKey===e.key){if(r&&t.expandedKeys.has(e.key))return t.toggleKey(e.key),a.stopPropagation(),!0;if(!t.expandedKeys.has(e.key)&&e.parentKey&&t.collection.getItem(e.parentKey)?.type==="item")return t.selectionManager.setFocusedKey(e.parentKey),a.stopPropagation(),!0}return!1}function Ne(a){let t=null,e=null;do e=a.lastChild(),e&&(t=e);while(e);return t}function Pr(a,t){let e=t.getChildren?.(a.key),r=e?Array.from(e):[],i=r.length>0?r[0]:null,l=[];for(;i;)l.push(i),i=i.nextKey!=null?t.getItem(i.nextKey):null;return l}function Ir(a,t){let{key:e}=a;const{checkboxProps:r}=pr(a,t);return{checkboxProps:{...r,"aria-labelledby":`${r.id} ${ke(t,e)}`}}}const Sr=b.createContext(null),Dr=b.forwardRef(function(t,e){return[t,e]=Ae(t,e,Sr),P.createElement(it,{content:P.createElement(ot,t)},r=>P.createElement(Er,{props:t,collection:r,gridListRef:e}))});function Er({props:a,collection:t,gridListRef:e}){[a,e]=Ae(a,e,He);let{shouldUseVirtualFocus:r,filter:i,disallowTypeAhead:l,UNSTABLE_focusOnEntry:s,...d}=a,{dragAndDropHooks:o,keyboardNavigationBehavior:c="arrow",layout:p="stack",orientation:m="vertical"}=a,{CollectionRoot:v,isVirtualized:h,layoutDelegate:f,dropTargetDelegate:x}=b.useContext(ue),g=ft({...d,collection:t,children:void 0,layoutDelegate:f}),k=ht(g,i),j=bt({usage:"search",sensitivity:"base"}),{disabledBehavior:T,disabledKeys:N}=k.selectionManager,{direction:$}=we(),y=b.useMemo(()=>new mt({collection:k.collection,collator:j,ref:e,disabledKeys:N,disabledBehavior:T,layoutDelegate:f,layout:p,orientation:m,direction:$}),[k.collection,e,p,m,N,T,f,j,$]),{gridProps:S}=kr({...d,keyboardDelegate:y,keyboardNavigationBehavior:p==="grid"?"tab":c,isVirtualized:h,shouldSelectOnPressUp:a.shouldSelectOnPressUp,disallowTypeAhead:l,UNSTABLE_focusOnEntry:s},k,e),M=k.selectionManager,_=!!o?.useDraggableCollectionState,C=!!o?.useDroppableCollectionState;b.useRef(_),b.useRef(C),b.useEffect(()=>{},[_,C]);let z,u,I,w=!1,D=null,E=b.useRef(null);if(_&&o){z=o.useDraggableCollectionState({collection:k.collection,selectionManager:M,preview:o.renderDragPreview?E:void 0}),o.useDraggableCollection({},z,e);let W=o.DragPreview;D=o.renderDragPreview?P.createElement(W,{ref:E},o.renderDragPreview):null}if(C&&o){u=o.useDroppableCollectionState({collection:k.collection,selectionManager:M});let W=o.dropTargetDelegate||x||new o.ListDropTargetDelegate(t,e,{layout:p,direction:$,orientation:m});I=o.useDroppableCollection({keyboardDelegate:y,dropTargetDelegate:W},u,e),w=u.isDropTarget({type:"root"})}let{focusProps:R,isFocused:K,isFocusVisible:F}=xe(),O=k.collection.size===0,H={isDropTarget:w,orientation:m,isEmpty:O,isFocused:K,isFocusVisible:F,layout:p,state:k},J=he({...a,children:void 0,defaultClassName:"react-aria-GridList",values:H}),re=null,ae=null;if(O&&a.renderEmptyState){let W=a.renderEmptyState(H);re=P.createElement("div",{role:"row","aria-rowindex":1,style:{display:"contents"}},P.createElement("div",{role:"gridcell",style:{display:"contents"}},W))}let Z=pe(a,{global:!0});return P.createElement(gt,null,P.createElement(be.div,{...te(Z,J,S,R,I?.collectionProps,ae),ref:e,slot:a.slot||void 0,onScroll:a.onScroll,"data-drop-target":w||void 0,"data-empty":O||void 0,"data-focused":K||void 0,"data-focus-visible":F||void 0,"data-layout":p,"data-orientation":m},P.createElement(Fe,{values:[[de,k],[fe,{dragAndDropHooks:o,dragState:z,dropState:u}],[yt,{render:jr}]]},C&&P.createElement(Tr,null),P.createElement(vt,null,P.createElement(v,{collection:k.collection,scrollRef:e,persistedKeys:$t(M,o,u),renderDropIndicator:xt(o,u)}))),re,D))}const Mr=Re(nt,function(t,e,r){let i=b.useContext(de),{dragAndDropHooks:l,dragState:s,dropState:d}=b.useContext(fe),o=Ke(e),{isVirtualized:c}=b.useContext(ue),p=s&&!(s.isDisabled||s.selectionManager.isDisabled(r.key)),{rowProps:m,gridCellProps:v,descriptionProps:h,...f}=wr({node:r,shouldSelectOnPressUp:!!s,isVirtualized:c,focusMode:t.focusMode,allowsArrowNavigation:t.allowsArrowNavigation},i,o),{hoverProps:x,isHovered:g}=lt({isDisabled:!f.allowsSelection&&!f.hasAction&&!p,onHoverStart:r.props.onHoverStart,onHoverChange:r.props.onHoverChange,onHoverEnd:r.props.onHoverEnd}),{isFocusVisible:k,focusProps:j}=xe(),{isFocusVisible:T,focusProps:N}=xe({within:!0}),{checkboxProps:$}=Ir({key:r.key},i),y=i.selectionManager.disabledBehavior==="all"&&f.isDisabled?{isDisabled:!0}:{},S=null;s&&l&&(S=l.useDraggableItem({key:r.key,hasDragButton:!0},s));let M=null,_=b.useRef(null),{visuallyHiddenProps:C}=Pe();d&&l&&(M=l.useDropIndicator({target:{type:"item",key:r.key,dropPosition:"on"}},d,_));let z=s&&s.isDragging(r.key),u=he({...t,id:void 0,children:r.rendered,defaultClassName:"react-aria-GridListItem",values:{...f,isHovered:g,isFocusVisible:k,isFocusVisibleWithin:T,selectionMode:i.selectionManager.selectionMode,selectionBehavior:i.selectionManager.selectionBehavior,allowsDragging:!!s,isDragging:z,isDropTarget:M?.isDropTarget,id:r.key,state:i}}),I=b.useRef(null);b.useEffect(()=>{s&&!I.current&&console.warn('Draggable items in a GridList must contain a