From afa2cdbc331b4de26759e37ef2c464353254d474 Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 16 Jul 2026 11:43:46 -0500 Subject: [PATCH] feat: add remote management identity features and update localization files for multiple languages --- Dockerfile | 1 + meshchatx.rsm | Bin 149784 -> 149784 bytes .../src/backend/management_identities.py | 5 ++- meshchatx/src/frontend/locales/de.json | 31 +++++++++++-- meshchatx/src/frontend/locales/es.json | 31 +++++++++++-- meshchatx/src/frontend/locales/fi.json | 31 +++++++++++-- meshchatx/src/frontend/locales/fr.json | 31 +++++++++++-- meshchatx/src/frontend/locales/it.json | 31 +++++++++++-- meshchatx/src/frontend/locales/nl.json | 31 +++++++++++-- meshchatx/src/frontend/locales/ru.json | 31 +++++++++++-- meshchatx/src/frontend/locales/zh.json | 31 +++++++++++-- tests/frontend/RNStatusPage.test.js | 42 +++++++++++++----- 12 files changed, 259 insertions(+), 37 deletions(-) diff --git a/Dockerfile b/Dockerfile index edcd95c1..cce44808 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,7 @@ COPY patches ./patches COPY scripts/fetch-micron-wasm.mjs scripts/fetch-micron-wasm.mjs COPY scripts/micron-wasm-resolve-bundled.mjs scripts/micron-wasm-resolve-bundled.mjs COPY scripts/micron-parser-go-version.mjs scripts/micron-parser-go-version.mjs +COPY scripts/build-visualiser-wasm.mjs scripts/build-visualiser-wasm.mjs COPY scripts/sync-meshchatx-docs.js scripts/sync-meshchatx-docs.js COPY scripts/pip_rns_remotes.py scripts/pip_rns_remotes.py COPY scripts/build/fetch_reticulum_manual.py scripts/build/fetch_reticulum_manual.py diff --git a/meshchatx.rsm b/meshchatx.rsm index be2e18c68e91a72b36c703fc4751af0d69d0c537..b9ecc665a3ca3a4180cd16038e08bad3be6e8be0 100644 GIT binary patch delta 952 zcmYL|KZqVg5XJefx|~K#5prH2F)0<2ot^zN8`1lOzzJF?76*qGJ2N{F36YqHhegtw z(mUY`2K}f?mB$?=Dlkd=MSI0^ZD-&?En7iZwqTr{`&eWFCF^%&8t5wo_^}ihyCjhj{kIN zZr|E_+ppbv>+${H-1y}9I~rNkbENV5$=e=P7&hN>}*Mxq7E=8^MDThE^R?43tQth!Vy z(kiLdR;mmM)>U%ln$@@_6E{{yDAE}*Tj9}=nQ33V<^RXV5L})ShcxctHVjf*`o`SUAf2X)UoHzJ%47w9HaE%*R5e@O2$co zu%U(#9Iz&EF$5V{au!QfrMC<;l%&Ay?WM_)*&)w6bw^Pec8)QC$xeeQ4+Gr+WSx7= z%pR2^$xuv!1Q=W8jM!r;|4OZ#I=^eILlZ!^-<&OD>&1qb$tj4-1!vWRmRK!~8hj5% zNS2Ul08s0j+u!~N?uL6?ZW#yU*nD=X7f-2&?0`T!R9AD>R?L^Rqf;x6l2Y)DS+r^& zvo8-!j;_4$;;uEN!Tydzs2K~DmWn_ho~j2QGq!-_^%}R@1Ml_kDBLE^S}Cw0*Yz^YfPv zZ9Efimv`>|^4E@sF5p%>|M0$eW!HubLrc>nF&=lKu}z zC5~tSQW%9**bt$0@UufXI&={Ty)}Qd06! zIF3M#S_lzG7!^^BEpskNWw4{6`s<_B4r%`BbaHThe9vUt@~Dw5bm25ykwzbYoUuVk z7KUJJElT7_Bl})$xx1)A>0TfauHO7+6YSY>;>fFKPMusb5UD~nW9P1wjGhjdzLg>%c()azzpD4mYYgq@s@t8nbw7AQLlg!9>{-Z z!3E8kRl%ebufwLAffkimN6%e6O{@(@bv{aL6h`ruy%+Wp_kVNcjdPpP01z#Lu?9() zh$KTB?o&OK1{R+OA*00wDFyA3v4q^KQSm(Uo4Y5EU;l18v43VUjvOg?PZ*`QA{Jc% jjdTnj8X3bAq>`v8RED;g{{}opEk!WM^|5oywWI$7&G8sC diff --git a/meshchatx/src/backend/management_identities.py b/meshchatx/src/backend/management_identities.py index 5b706bbc..442e7af8 100644 --- a/meshchatx/src/backend/management_identities.py +++ b/meshchatx/src/backend/management_identities.py @@ -45,7 +45,10 @@ def _identity_info(path: str, name: str) -> dict[str, Any] | None: if identity is None: return None try: - identity_hash = bytes(identity.hash).hex() + identity_hash_raw = identity.hash + if identity_hash_raw is None: + return None + identity_hash = bytes(identity_hash_raw).hex() except Exception: return None return { diff --git a/meshchatx/src/frontend/locales/de.json b/meshchatx/src/frontend/locales/de.json index b7fba512..c6e8fb22 100644 --- a/meshchatx/src/frontend/locales/de.json +++ b/meshchatx/src/frontend/locales/de.json @@ -490,7 +490,11 @@ "battery_unavailable": "Akkustatus nicht verfügbar", "battery_level_title": "Akku {percent}", "battery_charging_title": "Lädt {percent}", - "battery_discharging_title": "Akku {percent}" + "battery_discharging_title": "Akku {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Öffnen", @@ -2758,7 +2762,14 @@ "blackhole_publishing": "Veröffentlicht", "blackhole_inactive": "Inaktiv", "failed_refresh": "RNStatus konnte nicht aktualisiert werden", - "reloading": "RNS wird neu geladen..." + "reloading": "RNS wird neu geladen...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Textübersetzung", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Adresse konnte nicht kopiert werden", "config_dir": "Reticulum-Konfigurationsverzeichnis", "config_dir_placeholder": "Standard ist die Reticulum-Konfiguration der App", - "config_dir_hint": "Leer lassen, um die MeshChatX-Reticulum-Instanz zu teilen. Nur überschreiben, um ein separates Reticulum-Konfigurationsverzeichnis zu nutzen." + "config_dir_hint": "Leer lassen, um die MeshChatX-Reticulum-Instanz zu teilen. Nur überschreiben, um ein separates Reticulum-Konfigurationsverzeichnis zu nutzen.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/es.json b/meshchatx/src/frontend/locales/es.json index aa1220af..5bad2b5c 100644 --- a/meshchatx/src/frontend/locales/es.json +++ b/meshchatx/src/frontend/locales/es.json @@ -490,7 +490,11 @@ "battery_unavailable": "Estado de batería no disponible", "battery_level_title": "Batería {percent}", "battery_charging_title": "Cargando {percent}", - "battery_discharging_title": "En batería {percent}" + "battery_discharging_title": "En batería {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Abierto", @@ -2940,7 +2944,14 @@ "blackhole_publishing": "Publicando", "blackhole_inactive": "Inactivo", "failed_refresh": "Error al actualizar RNStatus", - "reloading": "Recargando RNS..." + "reloading": "Recargando RNS...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Traducción de texto", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "No se pudo copiar la dirección", "config_dir": "Directorio de configuración de Reticulum", "config_dir_placeholder": "Por defecto usa la configuración Reticulum de la app", - "config_dir_hint": "Déjalo en blanco para compartir la instancia Reticulum de MeshChatX. Sobrescribe solo para usar un directorio de configuración Reticulum aparte." + "config_dir_hint": "Déjalo en blanco para compartir la instancia Reticulum de MeshChatX. Sobrescribe solo para usar un directorio de configuración Reticulum aparte.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/fi.json b/meshchatx/src/frontend/locales/fi.json index 884d6c66..362dd022 100644 --- a/meshchatx/src/frontend/locales/fi.json +++ b/meshchatx/src/frontend/locales/fi.json @@ -490,7 +490,11 @@ "battery_unavailable": "Akun tila ei ole saatavilla", "battery_level_title": "Akku {percent}", "battery_charging_title": "Lataa {percent}", - "battery_discharging_title": "Akulla {percent}" + "battery_discharging_title": "Akulla {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Avaa", @@ -3130,7 +3134,14 @@ "blackhole_publishing": "Julkaistaan", "blackhole_inactive": "Epäaktiivinen", "failed_refresh": "RNStatusin päivitys epäonnistui", - "reloading": "Ladataan RNS uudelleen..." + "reloading": "Ladataan RNS uudelleen...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Tekstin käännös", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Osoitteen kopiointi epäonnistui", "config_dir": "Reticulum-asetushakemisto", "config_dir_placeholder": "Oletuksena sovelluksen Reticulum-asetukset", - "config_dir_hint": "Jätä tyhjäksi jakaaksesi MeshChatX:n Reticulum-instanssin. Korvaa vain, jos käytät erillistä Reticulum-asetushakemistoa." + "config_dir_hint": "Jätä tyhjäksi jakaaksesi MeshChatX:n Reticulum-instanssin. Korvaa vain, jos käytät erillistä Reticulum-asetushakemistoa.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/fr.json b/meshchatx/src/frontend/locales/fr.json index 30bf793d..ca2fb3d4 100644 --- a/meshchatx/src/frontend/locales/fr.json +++ b/meshchatx/src/frontend/locales/fr.json @@ -490,7 +490,11 @@ "battery_unavailable": "État de la batterie indisponible", "battery_level_title": "Batterie {percent}", "battery_charging_title": "En charge {percent}", - "battery_discharging_title": "Sur batterie {percent}" + "battery_discharging_title": "Sur batterie {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Ouvrir", @@ -2940,7 +2944,14 @@ "blackhole_publishing": "Publication", "blackhole_inactive": "Inactif", "failed_refresh": "Échec de l'actualisation de RNStatus", - "reloading": "Rechargement de RNS..." + "reloading": "Rechargement de RNS...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Traduction textuelle", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Échec de la copie de l'adresse", "config_dir": "Répertoire de configuration Reticulum", "config_dir_placeholder": "Par défaut: configuration Reticulum de l'app", - "config_dir_hint": "Laissez vide pour partager l'instance Reticulum de MeshChatX. Remplacez uniquement pour utiliser un répertoire de configuration Reticulum séparé." + "config_dir_hint": "Laissez vide pour partager l'instance Reticulum de MeshChatX. Remplacez uniquement pour utiliser un répertoire de configuration Reticulum séparé.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/it.json b/meshchatx/src/frontend/locales/it.json index 6b6d7805..d96aac05 100644 --- a/meshchatx/src/frontend/locales/it.json +++ b/meshchatx/src/frontend/locales/it.json @@ -490,7 +490,11 @@ "battery_unavailable": "Stato batteria non disponibile", "battery_level_title": "Batteria {percent}", "battery_charging_title": "In carica {percent}", - "battery_discharging_title": "A batteria {percent}" + "battery_discharging_title": "A batteria {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Apri", @@ -2992,7 +2996,14 @@ "blackhole_publishing": "Pubblicazione", "blackhole_inactive": "Inattivo", "failed_refresh": "Impossibile aggiornare RNStatus", - "reloading": "Ricaricamento RNS..." + "reloading": "Ricaricamento RNS...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Traduzione Testo", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Copia indirizzo non riuscita", "config_dir": "Directory di configurazione Reticulum", "config_dir_placeholder": "Impostazione predefinita: configurazione Reticulum dell'app", - "config_dir_hint": "Lascia vuoto per condividere l'istanza Reticulum di MeshChatX. Sovrascrivi solo per usare una directory di configurazione Reticulum separata." + "config_dir_hint": "Lascia vuoto per condividere l'istanza Reticulum di MeshChatX. Sovrascrivi solo per usare una directory di configurazione Reticulum separata.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/nl.json b/meshchatx/src/frontend/locales/nl.json index a8be421c..44b3a6e3 100644 --- a/meshchatx/src/frontend/locales/nl.json +++ b/meshchatx/src/frontend/locales/nl.json @@ -490,7 +490,11 @@ "battery_unavailable": "Batterijstatus niet beschikbaar", "battery_level_title": "Batterij {percent}", "battery_charging_title": "Opladen {percent}", - "battery_discharging_title": "Op batterij {percent}" + "battery_discharging_title": "Op batterij {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Openen", @@ -2940,7 +2944,14 @@ "blackhole_publishing": "Publiceren", "blackhole_inactive": "Inactief", "failed_refresh": "RNStatus vernieuwen mislukt", - "reloading": "RNS opnieuw laden..." + "reloading": "RNS opnieuw laden...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Tekstvertaling", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Adres kopiëren mislukt", "config_dir": "Reticulum-configuratiemap", "config_dir_placeholder": "Standaard: Reticulum-config van de app", - "config_dir_hint": "Laat leeg om de MeshChatX-Reticulum-instantie te delen. Overschrijf alleen om een aparte Reticulum-configuratiemap te gebruiken." + "config_dir_hint": "Laat leeg om de MeshChatX-Reticulum-instantie te delen. Overschrijf alleen om een aparte Reticulum-configuratiemap te gebruiken.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/ru.json b/meshchatx/src/frontend/locales/ru.json index a2e3d5b3..97d68433 100644 --- a/meshchatx/src/frontend/locales/ru.json +++ b/meshchatx/src/frontend/locales/ru.json @@ -490,7 +490,11 @@ "battery_unavailable": "Состояние батареи недоступно", "battery_level_title": "Батарея {percent}", "battery_charging_title": "Зарядка {percent}", - "battery_discharging_title": "От батареи {percent}" + "battery_discharging_title": "От батареи {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "Открыть", @@ -2758,7 +2762,14 @@ "blackhole_publishing": "Публикация", "blackhole_inactive": "Неактивно", "failed_refresh": "Не удалось обновить RNStatus", - "reloading": "Перезагрузка RNS..." + "reloading": "Перезагрузка RNS...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "Перевод текста", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "Не удалось скопировать адрес", "config_dir": "Каталог конфигурации Reticulum", "config_dir_placeholder": "По умолчанию: конфигурация Reticulum приложения", - "config_dir_hint": "Оставьте пустым, чтобы использовать общий экземпляр Reticulum MeshChatX. Указывайте путь только для отдельного каталога конфигурации Reticulum." + "config_dir_hint": "Оставьте пустым, чтобы использовать общий экземпляр Reticulum MeshChatX. Указывайте путь только для отдельного каталога конфигурации Reticulum.", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/meshchatx/src/frontend/locales/zh.json b/meshchatx/src/frontend/locales/zh.json index 0755704a..3a13cac2 100644 --- a/meshchatx/src/frontend/locales/zh.json +++ b/meshchatx/src/frontend/locales/zh.json @@ -490,7 +490,11 @@ "battery_unavailable": "无法获取电池状态", "battery_level_title": "电池 {percent}", "battery_charging_title": "充电中 {percent}", - "battery_discharging_title": "使用电池 {percent}" + "battery_discharging_title": "使用电池 {percent}", + "remote_management_allowed": "Remote management allow-list", + "remote_management_allowed_description": "Identity hashes allowed to query this instance remotely with rnstatus/rnpath. One 32-character hex hash per line.", + "remote_management_allowed_placeholder": "9fb6d773498fb3feda407ed8ef2c3229", + "remote_management_allowed_save": "Save allow-list" }, "common": { "open": "打开", @@ -2940,7 +2944,14 @@ "blackhole_publishing": "发布中", "blackhole_inactive": "未激活", "failed_refresh": "刷新 RNStatus 失败", - "reloading": "正在重新加载 RNS..." + "reloading": "正在重新加载 RNS...", + "remote_query": "Remote query", + "remote_query_hint": "Query a remote transport instance that has remote management enabled and your management identity on its allow-list.", + "remote_transport_hash": "Remote transport identity hash", + "remote_transport_placeholder": "32-character hex hash", + "remote_timeout": "Timeout (seconds)", + "remote_active": "Showing remote status for {hash}", + "use_local": "Use local instance" }, "translator": { "text_translation": "文本翻译", @@ -3686,6 +3697,20 @@ "failed_to_copy_address": "复制地址失败", "config_dir": "Reticulum 配置目录", "config_dir_placeholder": "默认为应用的 Reticulum 配置", - "config_dir_hint": "留空以共享 MeshChatX 的 Reticulum 实例。仅在需要单独的 Reticulum 配置目录时覆盖。" + "config_dir_hint": "留空以共享 MeshChatX 的 Reticulum 实例。仅在需要单独的 Reticulum 配置目录时覆盖。", + "interactive": "Interactive mode (-x)", + "timeout": "Connect timeout (seconds)", + "result_timeout": "Result download timeout (seconds)", + "stdout_limit": "Stdout limit (bytes)", + "stderr_limit": "Stderr limit (bytes)" + }, + "remote_mgmt": { + "management_identity": "Management identity", + "select_identity": "Select identity file", + "create_identity": "Create", + "create_identity_prompt": "Name for the new management identity file", + "identity_created": "Management identity created", + "failed_load_identities": "Failed to load management identities", + "failed_create_identity": "Failed to create management identity" } } diff --git a/tests/frontend/RNStatusPage.test.js b/tests/frontend/RNStatusPage.test.js index 7ce15b8e..24bdcda2 100644 --- a/tests/frontend/RNStatusPage.test.js +++ b/tests/frontend/RNStatusPage.test.js @@ -52,6 +52,9 @@ describe("RNStatusPage.vue", () => { }, }); } + if (url === "/api/v1/reticulum/management-identities") { + return Promise.resolve({ data: { identities: [] } }); + } return Promise.resolve({ data: {} }); }); }); @@ -83,14 +86,22 @@ describe("RNStatusPage.vue", () => { }); it("labels disabled blackhole as Inactive", async () => { - axiosMock.get.mockResolvedValueOnce({ - data: { - interfaces: [], - link_count: 0, - blackhole_enabled: false, - blackhole_count: 0, - blackhole_sources: [], - }, + axiosMock.get.mockImplementation((url) => { + if (url === "/api/v1/rnstatus") { + return Promise.resolve({ + data: { + interfaces: [], + link_count: 0, + blackhole_enabled: false, + blackhole_count: 0, + blackhole_sources: [], + }, + }); + } + if (url === "/api/v1/reticulum/management-identities") { + return Promise.resolve({ data: { identities: [] } }); + } + return Promise.resolve({ data: {} }); }); const wrapper = mountRNStatusPage(); await vi.waitFor(() => expect(wrapper.vm.isLoading).toBe(false)); @@ -123,12 +134,19 @@ describe("RNStatusPage.vue", () => { }); it("toasts on refresh failure", async () => { - axiosMock.get.mockRejectedValueOnce({ - response: { data: { message: "RNS stack is reloading" }, status: 503 }, + axiosMock.get.mockImplementation((url) => { + if (url === "/api/v1/rnstatus") { + return Promise.reject({ + response: { data: { message: "RNS stack is reloading" }, status: 503 }, + }); + } + if (url === "/api/v1/reticulum/management-identities") { + return Promise.resolve({ data: { identities: [] } }); + } + return Promise.resolve({ data: {} }); }); const wrapper = mountRNStatusPage(); - await vi.waitFor(() => expect(wrapper.vm.isLoading).toBe(false)); - expect(ToastUtils.error).toHaveBeenCalled(); + await vi.waitFor(() => expect(ToastUtils.error).toHaveBeenCalled()); const msg = ToastUtils.error.mock.calls[0][0]; expect(msg).toContain("Failed to refresh RNStatus"); expect(msg).toContain("RNS stack is reloading");