Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion front/php/server/util.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,72 @@ 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);
}

// -------------------------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions front/php/templates/language/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,7 @@
"settings_publishers_label": "Publishers",
"settings_readonly": "Can't READ or WRITE <code>app.conf</code>. Try restarting the container and read the <a href=\"https://docs.netalertx.com/FILE_PERMISSIONS\" target=\"_blank\">file permissions documentation</a>",
"settings_saved": "<br/>Settings saved. <br/> Reloading… <br/><i class=\"ion ion-ios-loop-strong fa-spin fa-2x fa-fw\"></i> <br/>",
"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. <b>Validation is not performed.</b>",
Expand Down
2 changes: 1 addition & 1 deletion front/plugins/avahi_scan/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
"string": "AVAHISCAN (Name discovery)"
"string": "AVAHISCAN (Naming)"
}
],
"icon": [
Expand Down
2 changes: 1 addition & 1 deletion front/plugins/nbtscan_scan/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
"string": "NBTSCAN (Name discovery)"
"string": "NBTSCAN (Naming)"
}
],
"icon": [
Expand Down
2 changes: 1 addition & 1 deletion front/plugins/nslookup_scan/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"display_name": [
{
"language_code": "en_us",
"string": "NSLOOKUP (Name discovery)"
"string": "NSLOOKUP (Naming)"
}
],
"icon": [
Expand Down
30 changes: 30 additions & 0 deletions front/plugins/ui_settings/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
]
Expand Down Expand Up @@ -704,6 +706,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."
}
]
}
]
}
30 changes: 22 additions & 8 deletions front/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,19 +615,33 @@ function: 'savesettings',
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')
Expand Down
Loading