Improve import/export

This commit is contained in:
Joey Yakimowich-Payne 2025-04-18 07:41:12 -06:00
commit 3a66505131
No known key found for this signature in database
GPG key ID: 6BFE655FA5ABD1E1
2 changed files with 75 additions and 82 deletions

View file

@ -338,23 +338,15 @@
<div class="config-content space-y-4 pt-2">
<div>
<button onclick="exportSettings()" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded">
Export Current Settings
Export Settings to File
</button>
</div>
<div>
<label for="settings-file-input" class="block text-sm font-medium text-gray-700">Or Load Settings from File:</label>
<input type="file" id="settings-file-input" name="settings-file-input" accept=".json, .txt" class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-purple-50 file:text-purple-700 hover:file:bg-purple-100">
<p class="mt-1 text-xs text-gray-500">Select a previously exported settings file (.json or .txt).</p>
</div>
<div>
<label for="settings-json" class="block text-sm font-medium text-gray-700">Settings Data (JSON):</label>
<textarea id="settings-json" rows="8" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-green-500 focus:border-green-500 sm:text-sm font-mono text-xs" placeholder="Click 'Export' to view settings here, or paste exported settings to import."></textarea>
<p class="mt-1 text-xs text-gray-500">Copy this text to save your settings, or paste previously exported settings here and click 'Import'.</p>
<p class="mt-1 text-xs text-gray-500">Saves all current settings to a downloadable .json file.</p>
</div>
<div>
<button onclick="importSettings()" class="w-full bg-purple-500 hover:bg-purple-600 text-white font-bold py-2 px-4 rounded">
Import Settings from Above
Import Settings from File
</button>
<p class="mt-1 text-xs text-gray-500">Loads settings from a previously exported .json file, overwriting current settings.</p>
</div>
</div>
</details>

View file

@ -1805,78 +1805,79 @@ function exportSettings() {
}
function importSettings() {
const settingsJson = document.getElementById('settings-json');
let parsedSettings;
try {
parsedSettings = JSON.parse(settingsJson.value);
if (typeof parsedSettings !== 'object' || parsedSettings === null) {
throw new Error('Imported data is not a valid JSON object.');
}
} catch (e) {
showNotification(`Error parsing settings JSON: ${e.message}`, 'error');
return;
}
// Create a temporary file input element
const tempInput = document.createElement('input');
tempInput.type = 'file';
tempInput.accept = '.json,.txt'; // Accept JSON or text files
tempInput.style.display = 'none'; // Hide the element
if (confirm('Importing these settings will OVERWRITE your current settings and reload the page. Are you sure you want to continue?')) {
const prefix = 'beango_';
const keysToRemove = [];
// 1. Clear existing beango settings first
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith(prefix)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => localStorage.removeItem(key));
// 2. Import new settings
let importCount = 0;
for (const key in parsedSettings) {
// Basic validation: Ensure the key starts with the prefix and has a value
if (key.startsWith(prefix) && parsedSettings.hasOwnProperty(key) && parsedSettings[key] !== undefined && parsedSettings[key] !== null) {
const value = parsedSettings[key];
// Store arrays/objects as JSON strings, others as plain strings
const valueToStore = (typeof value === 'object') ? JSON.stringify(value) : String(value);
localStorage.setItem(key, valueToStore);
importCount++;
} else {
console.warn(`Skipping import for invalid key or value: ${key}`);
}
}
showNotification(`Successfully imported ${importCount} settings. Reloading...`, 'success', 1500);
// Use a short delay before reload
setTimeout(() => {
location.reload();
}, 1600);
}
}
// --- Settings File Input Listener ---
const settingsFileInput = document.getElementById('settings-file-input');
if (settingsFileInput) {
settingsFileInput.addEventListener('change', function(event) {
tempInput.addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const settingsTextarea = document.getElementById('settings-json');
if (settingsTextarea) {
settingsTextarea.value = e.target.result;
showNotification('Settings file loaded into textarea. Click Import to apply.', 'success');
} else {
showNotification('Error: Could not find settings textarea.', 'error');
}
// Clear the file input value so the same file can be selected again if needed
event.target.value = null;
};
reader.onerror = function() {
showNotification('Error reading settings file.', 'error');
event.target.value = null; // Clear on error too
};
reader.readAsText(file);
if (!file) {
return; // No file selected
}
const reader = new FileReader();
reader.onload = function(e) {
const fileContent = e.target.result;
let parsedSettings;
try {
parsedSettings = JSON.parse(fileContent);
if (typeof parsedSettings !== 'object' || parsedSettings === null) {
throw new Error('Imported file does not contain a valid JSON object.');
}
} catch (err) {
showNotification(`Error parsing settings file: ${err.message}`, 'error');
return;
}
// Confirmation before overwriting
if (confirm('Importing settings from this file will OVERWRITE your current settings and reload the page. Are you sure?')) {
const prefix = 'beango_';
const keysToRemove = [];
// 1. Clear existing settings
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith(prefix)) {
keysToRemove.push(key);
}
}
keysToRemove.forEach(key => localStorage.removeItem(key));
// 2. Import new settings
let importCount = 0;
for (const key in parsedSettings) {
if (key.startsWith(prefix) && parsedSettings.hasOwnProperty(key) && parsedSettings[key] !== undefined && parsedSettings[key] !== null) {
const value = parsedSettings[key];
const valueToStore = (typeof value === 'object') ? JSON.stringify(value) : String(value);
localStorage.setItem(key, valueToStore);
importCount++;
} else {
console.warn(`Skipping import for invalid key or value: ${key}`);
}
}
showNotification(`Successfully imported ${importCount} settings from ${file.name}. Reloading...`, 'success', 1500);
setTimeout(() => {
location.reload();
}, 1600);
}
};
reader.onerror = function() {
showNotification('Error reading the selected file.', 'error');
};
reader.readAsText(file); // Read the file as text
// Clean up the temporary input element
document.body.removeChild(tempInput);
});
// Append to body and trigger click to open file dialog
document.body.appendChild(tempInput);
tempInput.click();
}