From 300a67d2476bf8b9831be4f5523e391c5118490e Mon Sep 17 00:00:00 2001 From: DJP Date: Thu, 16 Oct 2025 18:40:59 -0400 Subject: [PATCH] Add Reset to Factory Defaults button with double confirmation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Features: - Renamed "Reload from Server" to "Refresh Display" for clarity - Added "Reset to Factory Defaults" button with warning icon - Red danger button styling (matches warning theme) - Double confirmation dialog to prevent accidental resets - Backend endpoint to restore original 8 platforms (21 configurations) - Deletes custom platform_specs.json file - Restores L'Oréal documentation specifications Functionality: - "Refresh Display" - Reloads current specs from backend (no changes) - "Reset to Factory Defaults" - Deletes ALL custom platforms and restores original 21 configs - Custom platforms are saved until factory reset is triggered - Factory defaults stored at server startup for restoration Safety features: - Two confirmation dialogs - Clear warning messages - Success feedback showing platform count restored 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- backend/app.py | 26 ++++++++++++++++++++++++++ frontend/admin.css | 12 ++++++++++++ frontend/admin.html | 3 ++- frontend/admin.js | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/backend/app.py b/backend/app.py index ffc7dcc..5f0b680 100644 --- a/backend/app.py +++ b/backend/app.py @@ -22,6 +22,10 @@ from platform_specs import ( app = Flask(__name__) CORS(app) +# Store factory defaults (original specs from platform_specs.py) +import copy +FACTORY_DEFAULTS = copy.deepcopy(PLATFORM_SPECS) + # Configuration UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads') OUTPUT_FOLDER = os.path.join(os.path.dirname(__file__), 'outputs') @@ -420,6 +424,28 @@ def admin_import_specs(): return jsonify({'error': str(e)}), 500 +@app.route('/api/admin/reset-factory', methods=['POST']) +def admin_reset_factory(): + """Reset platform specifications to factory defaults""" + try: + # Restore from factory defaults + PLATFORM_SPECS.clear() + PLATFORM_SPECS.update(copy.deepcopy(FACTORY_DEFAULTS)) + + # Delete the saved JSON file if it exists + if os.path.exists(SPECS_FILE): + os.remove(SPECS_FILE) + + return jsonify({ + 'success': True, + 'message': 'Platform specifications reset to factory defaults', + 'platforms_count': len(PLATFORM_SPECS) + }) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + if __name__ == '__main__': # Load specs from file if exists saved_specs = load_specs_from_file() diff --git a/frontend/admin.css b/frontend/admin.css index 717ea39..056f952 100644 --- a/frontend/admin.css +++ b/frontend/admin.css @@ -82,6 +82,18 @@ min-width: 200px; } +.btn-danger { + background-color: transparent; + color: #ff0000; + border: 2px solid #ff0000; +} + +.btn-danger:hover { + background-color: #ff0000; + color: white; + border-color: #ff0000; +} + /* Platforms Section */ .platforms-section { margin-bottom: 3rem; diff --git a/frontend/admin.html b/frontend/admin.html index b313a19..c22b0e5 100644 --- a/frontend/admin.html +++ b/frontend/admin.html @@ -50,7 +50,8 @@ - + + diff --git a/frontend/admin.js b/frontend/admin.js index 47a4e77..e7e1c31 100644 --- a/frontend/admin.js +++ b/frontend/admin.js @@ -20,6 +20,7 @@ function setupEventListeners() { document.getElementById('importBtn').addEventListener('click', () => document.getElementById('importFile').click()); document.getElementById('importFile').addEventListener('change', importSpecs); document.getElementById('reloadBtn').addEventListener('click', loadPlatforms); + document.getElementById('resetFactoryBtn').addEventListener('click', resetToFactory); document.getElementById('closeModal').addEventListener('click', closeModal); document.getElementById('cancelBtn').addEventListener('click', closeModal); document.getElementById('addFormatBtn').addEventListener('click', addFormatConfig); @@ -387,6 +388,43 @@ async function importSpecs(e) { e.target.value = ''; // Reset file input } +// Reset to Factory Defaults +async function resetToFactory() { + const confirmed = confirm( + '⚠️ WARNING: This will DELETE all custom platforms and restore the original 8 platforms (21 configurations) from the L\'Oréal documentation.\n\n' + + 'This action cannot be undone unless you have exported your current specifications.\n\n' + + 'Do you want to continue?' + ); + + if (!confirmed) return; + + // Double confirmation for safety + const doubleConfirm = confirm( + 'Are you ABSOLUTELY SURE?\n\n' + + 'All custom platforms will be permanently deleted.\n\n' + + 'Click OK to reset to factory defaults.' + ); + + if (!doubleConfirm) return; + + try { + const response = await fetch(`${API_BASE}/admin/reset-factory`, { + method: 'POST' + }); + + const result = await response.json(); + + if (result.success) { + showMessage(`✅ Reset successful! Restored ${result.platforms_count} original platforms.`, 'success'); + loadPlatforms(); + } else { + showMessage('Error resetting: ' + result.error, 'error'); + } + } catch (error) { + showMessage('Error resetting to factory: ' + error.message, 'error'); + } +} + // UI Helpers function showMessage(message, type = 'success') { const existingMessage = document.querySelector('.message');