diff --git a/app/utils/settings_sync.py b/app/utils/settings_sync.py
index 893e14ce..3298c189 100644
--- a/app/utils/settings_sync.py
+++ b/app/utils/settings_sync.py
@@ -38,7 +38,9 @@ _last_seen_version: str = ""
def notify_settings_updated() -> None:
"""
- Publish a settings-updated signal by updating the Redis version key.
+ Publish a settings-updated signal by updating the Redis version key, and
+ immediately reload the in-process ``settings`` singleton so the API
+ process serves fresh values without a restart.
Call this after every successful settings write so that all worker
processes know they need to reload their in-memory configuration.
@@ -56,6 +58,19 @@ def notify_settings_updated() -> None:
except Exception as exc:
logger.warning(f"Could not publish settings update to Redis: {exc}")
+ # Reload the in-process settings singleton immediately so the API node
+ # returns updated values (e.g. oauth_provider_name on the login page)
+ # without needing a restart. Workers use the task_prerun signal handler
+ # instead, so this only affects the API/web process.
+ try:
+ from app.config import settings
+ from app.utils.config_loader import reload_settings_from_db
+
+ reload_settings_from_db(settings)
+ logger.debug("In-process settings reloaded after settings update")
+ except Exception as exc:
+ logger.warning(f"Could not reload in-process settings: {exc}")
+
def register_settings_reload_signal() -> None:
"""
diff --git a/frontend/templates/settings.html b/frontend/templates/settings.html
index 36afbd72..b35ccefe 100644
--- a/frontend/templates/settings.html
+++ b/frontend/templates/settings.html
@@ -185,7 +185,7 @@
{% endif %}
-
+
+
@@ -233,9 +245,11 @@ function settingsApp() {
return {
formData: {},
originalData: {},
+ isDbOverride: {},
showPassword: {},
saving: false,
savingKey: null,
+ revertingKey: null,
showAlert: false,
alertType: 'success',
alertTitle: '',
@@ -247,6 +261,7 @@ function settingsApp() {
{% for setting in settings_list %}
this.formData['{{ setting.key }}'] = {{ setting.display_value|tojson }};
this.originalData['{{ setting.key }}'] = {{ setting.display_value|tojson }};
+ this.isDbOverride['{{ setting.key }}'] = {{ (setting.source == 'database')|tojson }};
this.showPassword['{{ setting.key }}'] = false;
{% endfor %}
{% endfor %}
@@ -297,6 +312,7 @@ function settingsApp() {
if (response.ok && result.success) {
this.originalData[key] = value;
+ this.isDbOverride[key] = true;
let message = `Setting '${key}' saved successfully.`;
if (result.restart_required) {
message += ' Please restart the application for this change to take effect.';
@@ -313,6 +329,30 @@ function settingsApp() {
}
},
+ async revertSetting(key) {
+ this.revertingKey = key;
+ this.hideAlert();
+
+ try {
+ const response = await fetch(`/api/settings/${key}`, {
+ method: 'DELETE',
+ });
+
+ if (response.ok) {
+ // Reload the page so the ENV/default value and source badge refresh
+ window.location.reload();
+ } else {
+ const result = await response.json();
+ this.showErrorAlert('Revert Failed', result.detail || 'Unknown error');
+ this.revertingKey = null;
+ }
+ } catch (error) {
+ console.error('Error reverting setting:', error);
+ this.showErrorAlert('Error', 'Failed to revert setting. Please try again.');
+ this.revertingKey = null;
+ }
+ },
+
async saveSettings() {
this.saving = true;
this.hideAlert();
@@ -345,7 +385,10 @@ function settingsApp() {
const result = await response.json();
if (response.ok && result.success) {
- this.originalData = { ...this.formData };
+ for (const updated of result.updated) {
+ this.originalData[updated.key] = updated.value;
+ this.isDbOverride[updated.key] = true;
+ }
let message = `${result.updated.length} setting(s) updated successfully.`;
if (result.restart_required) {
message += ' Please restart the application for changes to take effect.';