From 102a62c8b7edae2a8752f5a04e05f0fe7c18d6cd Mon Sep 17 00:00:00 2001
From: "Jokob @NetAlertX" <96159884+jokob-sk@users.noreply.github.com>
Date: Sun, 21 Jun 2026 00:57:17 +0000
Subject: [PATCH 1/3] FE: enhance settings save functionality with reload wait
detection and background processing
---
front/php/server/util.php | 61 ++++++++++++++++++++++++-
front/php/templates/language/en_us.json | 1 +
front/settings.php | 30 ++++++++----
server/conf.py | 1 +
server/initialise.py | 10 ++++
5 files changed, 94 insertions(+), 9 deletions(-)
diff --git a/front/php/server/util.php b/front/php/server/util.php
index c9b7b38c..75c8d86c 100755
--- a/front/php/server/util.php
+++ b/front/php/server/util.php
@@ -166,15 +166,74 @@ function saveSettings()
copy($fullConfPath, $fullConfPath . ".bak");
}
+ // Detect whether the frontend needs to block-wait for backend reload
+ $requiresReloadWait = getReloadWaitRequired($decodedSettings);
+
// Open the file for writing without changing permissions
$file = fopen($fullConfPath, "w") or die("Unable to open file!");
fwrite($file, $txt);
fclose($file);
- echo "OK";
+ echo json_encode(['success' => true, 'requiresReloadWait' => $requiresReloadWait]);
}
+// -------------------------------------------------------------------------------------------
+// Determines if the frontend must wait (block) for the backend to finish reloading after a
+// settings save. Blocking is required when LOADED_PLUGINS changes or UI_WAIT_FOR_SETTINGS
+// is explicitly enabled. Defaults to true (safe) on any parsing error.
+function getReloadWaitRequired($decodedSettings) {
+ $newLoadedPlugins = null;
+ $uiWaitForSettings = false;
+
+ foreach ($decodedSettings as $setting) {
+ if ($setting[1] === 'LOADED_PLUGINS') {
+ $newLoadedPlugins = $setting[3];
+ }
+ if ($setting[1] === 'UI_WAIT_FOR_SETTINGS') {
+ $uiWaitForSettings = ($setting[3] === true || $setting[3] === 1
+ || strtolower((string)$setting[3]) === 'true');
+ }
+ }
+
+ if ($uiWaitForSettings) {
+ return true;
+ }
+
+ $oldLoadedPlugins = getSettingValue('LOADED_PLUGINS');
+
+ // If the old value couldn't be read, default to blocking (safe).
+ if (strpos((string)$oldLoadedPlugins, 'Could not') !== false) {
+ return true;
+ }
+
+ return normalizePluginList($oldLoadedPlugins) !== normalizePluginList($newLoadedPlugins);
+}
+
+// -------------------------------------------------------------------------------------------
+// Normalise a plugin list value (PHP array, JSON array, or Python-style list) to a sorted
+// JSON string for reliable equality comparison.
+function normalizePluginList($value) {
+ if ($value === null || $value === '') {
+ return '[]';
+ }
+ if (is_array($value)) {
+ $arr = $value;
+ } else {
+ $arr = json_decode($value, true);
+ if (!is_array($arr)) {
+ // Handle Python-style single-quoted lists: ['A','B']
+ $jsonStr = str_replace("'", '"', (string)$value);
+ $arr = json_decode($jsonStr, true);
+ }
+ if (!is_array($arr)) {
+ return trim((string)$value);
+ }
+ }
+ sort($arr);
+ return json_encode($arr);
+}
+
// -------------------------------------------------------------------------------------------
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
// check server/api_server/api_server_start.py for equivalents
diff --git a/front/php/templates/language/en_us.json b/front/php/templates/language/en_us.json
index 102c7cb2..cfefcac5 100755
--- a/front/php/templates/language/en_us.json
+++ b/front/php/templates/language/en_us.json
@@ -807,6 +807,7 @@
"settings_publishers_label": "Publishers",
"settings_readonly": "Can't READ or WRITE app.conf. Try restarting the container and read the file permissions documentation",
"settings_saved": "
Settings saved.
Reloading…
",
+ "settings_saved_background": "Settings saved. Changes are being applied in the background.",
"settings_system_icon": "fa-solid fa-gear",
"settings_system_label": "System",
"settings_update_item_warning": "Update the value below. Be careful to follow the previous format. Validation is not performed.",
diff --git a/front/settings.php b/front/settings.php
index 03d3e291..0be479ce 100755
--- a/front/settings.php
+++ b/front/settings.php
@@ -615,19 +615,33 @@ $settingsJSON_DB = json_encode($settings, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX
settings: JSON.stringify(settingsArray) },
success: function(data, textStatus) {
- if(data == "OK")
- {
- // showMessage (getString("settings_saved"), 5000, "modal_grey");
+ // Parse response: support both legacy "OK" string and new JSON format
+ let saveSucceeded = false;
+ let requiresReloadWait = true; // safe default
+
+ if (data === "OK") {
+ saveSucceeded = true;
+ } else {
+ let parsed = null;
+ try { parsed = (typeof data === 'object') ? data : JSON.parse(data); } catch(e) {}
+ if (parsed && parsed.success === true) {
+ saveSucceeded = true;
+ requiresReloadWait = parsed.requiresReloadWait === true;
+ }
+ }
+
+ if (saveSucceeded) {
// Remove navigation prompt "Are you sure you want to leave..."
window.onbeforeunload = null;
- // Reloads the current page
- // setTimeout("clearCache()", 5000);
-
write_notification(`[Settings] Settings saved by the user`, 'info')
- clearCache()
- } else{
+ if (requiresReloadWait) {
+ clearCache()
+ } else {
+ showMessage(getString("settings_saved_background"), 5000, "modal_green");
+ }
+ } else {
// something went wrong
write_notification("[Important] Please take a screenshot of the Console tab in the browser (F12) and next error. Submit it (with the nginx and php error logs) as a new issue here: https://github.com/netalertx/NetAlertX/issues", 'interrupt')
write_notification(data, 'interrupt')
diff --git a/server/conf.py b/server/conf.py
index 4eda3e84..c28dfc9c 100755
--- a/server/conf.py
+++ b/server/conf.py
@@ -32,6 +32,7 @@ SCAN_SUBNETS = ["192.168.1.0/24 --interface=eth1", "192.168.1.0/24 --interface=e
LOG_LEVEL = "verbose"
TIMEZONE = "Europe/Berlin"
UI_LANG = "English (en_us)"
+UI_WAIT_FOR_SETTINGS = False
UI_PRESENCE = ["online", "offline", "archived"]
UI_MY_DEVICES = ["online", "offline", "archived", "new", "down"]
UI_NOT_RANDOM_MAC = []
diff --git a/server/initialise.py b/server/initialise.py
index bf53c494..0cc06a21 100755
--- a/server/initialise.py
+++ b/server/initialise.py
@@ -452,6 +452,16 @@ def importConfigs(pm, db, all_plugins):
"UI",
)
+ conf.UI_WAIT_FOR_SETTINGS = ccd(
+ "UI_WAIT_FOR_SETTINGS",
+ False,
+ c_d,
+ "Wait for settings reload",
+ '{"dataType":"boolean", "elements": [{"elementType" : "checkbox", "elementOptions" : [] ,"transformers": []}]}',
+ "[]",
+ "UI",
+ )
+
# Init timezone in case it changed and handle invalid values
try:
if conf.TIMEZONE not in all_timezones:
From f52e303c193ae44e573ddcd6893e5fb5883dfd87 Mon Sep 17 00:00:00 2001
From: "Jokob @NetAlertX" <96159884+jokob-sk@users.noreply.github.com>
Date: Sun, 21 Jun 2026 01:08:56 +0000
Subject: [PATCH 2/3] FE: add 'Wait for settings reload' option to UI settings
---
front/plugins/ui_settings/config.json | 28 +++++++++++++++++++++++++++
server/conf.py | 1 -
server/initialise.py | 10 ----------
3 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/front/plugins/ui_settings/config.json b/front/plugins/ui_settings/config.json
index 8bb9c07f..d8efd580 100755
--- a/front/plugins/ui_settings/config.json
+++ b/front/plugins/ui_settings/config.json
@@ -704,6 +704,34 @@
"string": "Based on which value should the network topology view be ordered."
}
]
+ },
+ {
+ "function": "WAIT_FOR_SETTINGS",
+ "type": {
+ "dataType": "boolean",
+ "elements": [
+ {
+ "elementType": "input",
+ "elementOptions": [{ "type": "checkbox" }],
+ "transformers": []
+ }
+ ]
+ },
+ "default_value": false,
+ "options": [],
+ "localized": ["name", "description"],
+ "name": [
+ {
+ "language_code": "en_us",
+ "string": "Wait for settings reload"
+ }
+ ],
+ "description": [
+ {
+ "language_code": "en_us",
+ "string": "When enabled, the UI blocks after saving settings until the backend finishes reloading. When disabled (default), the UI returns immediately for most changes and only waits when plugin configuration changes."
+ }
+ ]
}
]
}
diff --git a/server/conf.py b/server/conf.py
index c28dfc9c..4eda3e84 100755
--- a/server/conf.py
+++ b/server/conf.py
@@ -32,7 +32,6 @@ SCAN_SUBNETS = ["192.168.1.0/24 --interface=eth1", "192.168.1.0/24 --interface=e
LOG_LEVEL = "verbose"
TIMEZONE = "Europe/Berlin"
UI_LANG = "English (en_us)"
-UI_WAIT_FOR_SETTINGS = False
UI_PRESENCE = ["online", "offline", "archived"]
UI_MY_DEVICES = ["online", "offline", "archived", "new", "down"]
UI_NOT_RANDOM_MAC = []
diff --git a/server/initialise.py b/server/initialise.py
index 0cc06a21..bf53c494 100755
--- a/server/initialise.py
+++ b/server/initialise.py
@@ -452,16 +452,6 @@ def importConfigs(pm, db, all_plugins):
"UI",
)
- conf.UI_WAIT_FOR_SETTINGS = ccd(
- "UI_WAIT_FOR_SETTINGS",
- False,
- c_d,
- "Wait for settings reload",
- '{"dataType":"boolean", "elements": [{"elementType" : "checkbox", "elementOptions" : [] ,"transformers": []}]}',
- "[]",
- "UI",
- )
-
# Init timezone in case it changed and handle invalid values
try:
if conf.TIMEZONE not in all_timezones:
From 39024d37dee1dbc2360b05d46ece214620f71ecf Mon Sep 17 00:00:00 2001
From: jokob-sk
Date: Sun, 21 Jun 2026 11:18:34 +1000
Subject: [PATCH 3/3] PLG: config cleanups
---
front/plugins/avahi_scan/config.json | 2 +-
front/plugins/nbtscan_scan/config.json | 2 +-
front/plugins/nslookup_scan/config.json | 2 +-
front/plugins/ui_settings/config.json | 2 ++
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/front/plugins/avahi_scan/config.json b/front/plugins/avahi_scan/config.json
index 7bbc1072..6dbc17dd 100755
--- a/front/plugins/avahi_scan/config.json
+++ b/front/plugins/avahi_scan/config.json
@@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
- "string": "AVAHISCAN (Name discovery)"
+ "string": "AVAHISCAN (Naming)"
}
],
"icon": [
diff --git a/front/plugins/nbtscan_scan/config.json b/front/plugins/nbtscan_scan/config.json
index f7f4401d..fe64e883 100755
--- a/front/plugins/nbtscan_scan/config.json
+++ b/front/plugins/nbtscan_scan/config.json
@@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
- "string": "NBTSCAN (Name discovery)"
+ "string": "NBTSCAN (Naming)"
}
],
"icon": [
diff --git a/front/plugins/nslookup_scan/config.json b/front/plugins/nslookup_scan/config.json
index 83ce0a29..7aec0c11 100755
--- a/front/plugins/nslookup_scan/config.json
+++ b/front/plugins/nslookup_scan/config.json
@@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
- "string": "NSLOOKUP (Name discovery)"
+ "string": "NSLOOKUP (Naming)"
}
],
"icon": [
diff --git a/front/plugins/ui_settings/config.json b/front/plugins/ui_settings/config.json
index d8efd580..b3cfaaf2 100755
--- a/front/plugins/ui_settings/config.json
+++ b/front/plugins/ui_settings/config.json
@@ -264,11 +264,13 @@
"localized": [],
"name": [
{
+ "language_code": "en_us",
"string": "Default page size"
}
],
"description": [
{
+ "language_code": "en_us",
"string": "Default number of items shown in tables per page, for example in teh Devices lists."
}
]