Skip to content

Commit 5f12b98

Browse files
rcourtmanclaude
andcommitted
fix: prevent caching empty form values to avoid confusing configuration display
- Added hasSignificantConfiguration() to check if form data contains meaningful values - Only cache form data when there's actual configuration (e.g., non-empty host fields) - Clear cache when no significant data exists to prevent empty value restoration - Fixes issue where empty default values were cached and restored, appearing as lost config - Improves user experience by only preserving actual user input 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 76922fd commit 5f12b98

File tree

1 file changed

+136
-1
lines changed

1 file changed

+136
-1
lines changed

src/public/js/ui/settings.js

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ PulseApp.ui.settings = (() => {
77
let latestReleaseData = null; // Store the latest release data
88
let updateCache = new Map(); // Cache update check results to reduce API calls
99
let updateCheckTimeout = null; // Debounce rapid channel changes
10+
let formDataCache = {}; // Store form data between tab switches
1011

1112
function init() {
1213
if (isInitialized) return;
@@ -72,6 +73,9 @@ PulseApp.ui.settings = (() => {
7273
}
7374

7475
function switchTab(tabName) {
76+
// Preserve current form data before switching tabs
77+
preserveCurrentFormData();
78+
7579
activeTab = tabName;
7680

7781
// Update tab buttons
@@ -92,6 +96,9 @@ PulseApp.ui.settings = (() => {
9296

9397
// Update content
9498
renderTabContent();
99+
100+
// Restore form data for the new tab
101+
restoreFormData();
95102
}
96103

97104
async function openModal() {
@@ -118,11 +125,17 @@ PulseApp.ui.settings = (() => {
118125
function closeModal() {
119126
console.log('[Settings] Closing modal...');
120127

128+
// Preserve current form data before closing
129+
preserveCurrentFormData();
130+
121131
const modal = document.getElementById('settings-modal');
122132
if (!modal) return;
123133

124134
modal.classList.add('hidden');
125135
modal.classList.remove('flex');
136+
137+
// Clear form data cache since modal is being closed
138+
formDataCache = {};
126139
}
127140

128141
async function loadConfiguration() {
@@ -177,6 +190,11 @@ PulseApp.ui.settings = (() => {
177190

178191
container.innerHTML = `<form id="settings-form" class="space-y-6">${content}</form>`;
179192

193+
// Restore form data after content is rendered
194+
setTimeout(() => {
195+
restoreFormData();
196+
}, 0);
197+
180198
// Load existing additional endpoints for Proxmox and PBS tabs
181199
if (activeTab === 'proxmox') {
182200
loadExistingPveEndpoints();
@@ -1326,7 +1344,9 @@ PulseApp.ui.settings = (() => {
13261344
saveButton.textContent = 'Saving...';
13271345

13281346
try {
1329-
const config = collectFormData();
1347+
// Preserve current tab data before collecting all data
1348+
preserveCurrentFormData();
1349+
const config = collectAllTabsData();
13301350

13311351
const response = await fetch('/api/config', {
13321352
method: 'POST',
@@ -1395,6 +1415,121 @@ PulseApp.ui.settings = (() => {
13951415
return config;
13961416
}
13971417

1418+
function collectAllTabsData() {
1419+
// Start with current form data and add cached data from other tabs
1420+
const currentFormConfig = collectFormData();
1421+
const allConfig = { ...currentFormConfig };
1422+
1423+
// Merge data from all cached tabs
1424+
Object.values(formDataCache).forEach(tabData => {
1425+
Object.entries(tabData).forEach(([name, value]) => {
1426+
// Only use cached value if not already set from current form
1427+
if (!allConfig.hasOwnProperty(name)) {
1428+
if (typeof value === 'boolean') {
1429+
allConfig[name] = value ? 'true' : 'false';
1430+
} else {
1431+
allConfig[name] = value;
1432+
}
1433+
}
1434+
});
1435+
});
1436+
1437+
console.log('[Settings] Collected data from all tabs:', allConfig);
1438+
return allConfig;
1439+
}
1440+
1441+
function preserveCurrentFormData() {
1442+
const form = document.getElementById('settings-form');
1443+
if (!form) return;
1444+
1445+
const formData = new FormData(form);
1446+
const currentTabData = {};
1447+
1448+
// Store all form field values
1449+
for (const [name, value] of formData.entries()) {
1450+
const field = form.querySelector(`[name="${name}"]`);
1451+
if (field) {
1452+
if (field.type === 'checkbox') {
1453+
currentTabData[name] = field.checked;
1454+
} else {
1455+
currentTabData[name] = value;
1456+
}
1457+
}
1458+
}
1459+
1460+
// Also store unchecked checkboxes
1461+
const checkboxes = form.querySelectorAll('input[type="checkbox"]');
1462+
checkboxes.forEach(checkbox => {
1463+
if (!checkbox.checked && !currentTabData.hasOwnProperty(checkbox.name)) {
1464+
currentTabData[checkbox.name] = false;
1465+
}
1466+
});
1467+
1468+
// Only cache data if it contains meaningful configuration
1469+
if (hasSignificantConfiguration(currentTabData, activeTab)) {
1470+
formDataCache[activeTab] = currentTabData;
1471+
console.log(`[Settings] Preserved data for tab '${activeTab}':`, currentTabData);
1472+
} else {
1473+
// Clear cache for this tab if no significant data
1474+
delete formDataCache[activeTab];
1475+
console.log(`[Settings] No significant data to preserve for tab '${activeTab}', cleared cache`);
1476+
}
1477+
}
1478+
1479+
function hasSignificantConfiguration(data, tabName) {
1480+
// Check if the data contains any non-empty, meaningful values
1481+
if (tabName === 'proxmox') {
1482+
// For Proxmox tab, require at least a host to be considered significant
1483+
return !!(data.PROXMOX_HOST && data.PROXMOX_HOST.trim()) ||
1484+
!!(data.PROXMOX_HOST_2 && data.PROXMOX_HOST_2.trim()) ||
1485+
!!(data.PROXMOX_HOST_3 && data.PROXMOX_HOST_3.trim());
1486+
} else if (tabName === 'pbs') {
1487+
// For PBS tab, require at least a host to be considered significant
1488+
return !!(data.PBS_HOST && data.PBS_HOST.trim()) ||
1489+
!!(data.PBS_HOST_2 && data.PBS_HOST_2.trim()) ||
1490+
!!(data.PBS_HOST_3 && data.PBS_HOST_3.trim());
1491+
} else if (tabName === 'alerts') {
1492+
// For alerts tab, any threshold value or email/webhook config is significant
1493+
return Object.keys(data).some(key => {
1494+
const value = data[key];
1495+
if (typeof value === 'string' && value.trim()) return true;
1496+
if (typeof value === 'boolean' && value) return true;
1497+
if (typeof value === 'number' && value > 0) return true;
1498+
return false;
1499+
});
1500+
}
1501+
1502+
// For other tabs, check if any field has a non-empty value
1503+
return Object.values(data).some(value => {
1504+
if (typeof value === 'string' && value.trim()) return true;
1505+
if (typeof value === 'boolean' && value) return true;
1506+
if (typeof value === 'number' && value !== 0) return true;
1507+
return false;
1508+
});
1509+
}
1510+
1511+
function restoreFormData() {
1512+
const form = document.getElementById('settings-form');
1513+
if (!form) return;
1514+
1515+
const savedData = formDataCache[activeTab];
1516+
if (!savedData) return;
1517+
1518+
console.log(`[Settings] Restoring data for tab '${activeTab}':`, savedData);
1519+
1520+
// Restore form field values
1521+
Object.entries(savedData).forEach(([name, value]) => {
1522+
const field = form.querySelector(`[name="${name}"]`);
1523+
if (field) {
1524+
if (field.type === 'checkbox') {
1525+
field.checked = value === true || value === 'true';
1526+
} else {
1527+
field.value = value || '';
1528+
}
1529+
}
1530+
});
1531+
}
1532+
13981533
function showMessage(message, type = 'info') {
13991534
// Find or create message container within the current tab
14001535
let container = document.getElementById('settings-message');

0 commit comments

Comments
 (0)