function loadConfig() { try { const headers = {}; if (hmac && hmac.length > 0) { headers['CTBREC-HMAC'] = CryptoJS.HmacSHA256('', hmac).toString(CryptoJS.enc.Base64); } fetch('../config', { method: 'GET', headers: headers, cache: 'no-cache' }) .then(response => { if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return response.json(); }) .then(data => { while (observableSettingsArray().length > 0) { observableSettingsArray.pop(); } for (let i = 0; i < data.length; i++) { let param = data[i]; param.ko_value = ko.observable(param.value); observableSettingsArray.push(param); } }) .catch(error => { if (console) console.log('Failed to load config:', error); }); } catch (e) { if (console) console.log('Unexpected error:', e); } } function saveConfig() { try { // Create new array with updated values let settings = observableSettingsArray().map(param => ({ key: param.key, type: param.type, value: param.ko_value() // Use observable value })); let msg = JSON.stringify(settings); console.log('Saving config JSON:', msg); const abortController = new AbortController(); const timeoutId = setTimeout(() => abortController.abort(), 60000); // 60 seconds timeout fetch('../config', { method: 'POST', headers: { 'Content-Type': 'application/json', 'CTBREC-HMAC': CryptoJS.HmacSHA256(msg, hmac) }, body: msg, signal: abortController.signal }) .then(response => { clearTimeout(timeoutId); // Clear timeout on success if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } return response.json(); }) .then(data => { // Update param.value to reflect saved values observableSettingsArray().forEach(param => { param.value = param.ko_value(); }); loadConfig(); $.notify('Configuration saved. You might have to restart the server.', 'info'); }) .catch(error => { clearTimeout(timeoutId); // Clear timeout on error if (console) console.log('Request failed:', error); $.notify(error.message || 'Unknown error: ' + (error.responseText || 'No response'), 'error'); }); } catch (e) { if (console) console.log('Unexpected error:', e); $.notify('Unexpected error: ' + e.message, 'error'); } } function notify(msg, type = 'info') { const toastEl = document.getElementById('toast'); toastEl.querySelector('.toast-body').textContent = msg; toastEl.classList.remove('bg-success', 'bg-danger', 'bg-info'); toastEl.classList.add(type === 'error' ? 'bg-danger' : type === 'info' ? 'bg-info' : 'bg-success', 'text-white'); const toast = new bootstrap.Toast(toastEl, { autohide: true, delay: 5000 }); toast.show(); document.getElementById('alert-container').appendChild(toastEl.parentElement); }