diff --git a/app/routes.py b/app/routes.py index c05f308..76f055f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -296,28 +296,49 @@ def delete_category(category_id): if category.is_root: return jsonify({'error': 'Cannot delete root category'}), 400 - # Get target category for documents if specified - new_category_id = request.args.get('new_category_id') - if new_category_id: - new_category = Category.query.filter_by(id=new_category_id, user_id=current_user.id).first() - if new_category: - # Reassign documents - for doc in category.documents: - doc.category_id = new_category.id - else: - # Move documents to no category + # Check if we should preserve contents + preserve_contents = request.args.get('preserve_contents', 'false').lower() == 'true' + + # Find parent category or root + parent_category = None + if category.parent_id: + parent_category = Category.query.filter_by(id=category.parent_id, user_id=current_user.id).first() + + if not parent_category: + # If no parent or parent not found, use root category + parent_category = Category.query.filter_by(user_id=current_user.id, is_root=True).first() + + if preserve_contents: + # Move documents to parent category for doc in category.documents: - doc.category_id = None - - # Also handle child categories - for child in category.children: - if new_category_id: - child.parent_id = new_category_id - else: - child.parent_id = None + doc.category_id = parent_category.id + + # Move child categories to parent + for child in category.children: + child.parent_id = parent_category.id + else: + # Delete all documents in this category + for doc in category.documents: + db.session.delete(doc) + + # Recursively delete subcategories and their documents + def delete_subcategories(parent): + for child in parent.children: + # Delete all documents in this subcategory + for doc in child.documents: + db.session.delete(doc) + # Recursively delete subcategories + delete_subcategories(child) + # Delete the subcategory itself + db.session.delete(child) + + # Start recursive deletion + delete_subcategories(category) + # Delete the category itself db.session.delete(category) db.session.commit() + return jsonify({'success': True}) @main.route('/api/search', methods=['GET']) diff --git a/app/templates/base.html b/app/templates/base.html index 3de4985..e68e656 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -397,23 +397,71 @@ const docActions = document.createElement('div'); docActions.className = 'actions absolute right-0 hidden group-hover:flex items-center bg-gray-800 px-1'; - // Edit doc button - const editDocButton = document.createElement('button'); - editDocButton.className = 'p-1 text-gray-500 hover:text-primary rounded transition-colors'; - editDocButton.title = 'Edit Document'; - editDocButton.innerHTML = ''; - editDocButton.addEventListener('click', function(e) { + // Edit document button + const editBtn = document.createElement('button'); + editBtn.className = 'p-1 text-gray-500 hover:text-primary rounded transition-colors'; + editBtn.title = 'Edit document'; + editBtn.innerHTML = ''; + editBtn.addEventListener('click', function(e) { e.preventDefault(); e.stopPropagation(); window.location.href = `/document/${doc.id}/edit`; }); - docActions.appendChild(editDocButton); + docActions.appendChild(editBtn); + + // Delete document button + const deleteBtn = document.createElement('button'); + deleteBtn.className = 'p-1 text-gray-500 hover:text-red-500 rounded transition-colors'; + deleteBtn.title = 'Delete document'; + deleteBtn.innerHTML = ''; + deleteBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + // Show confirmation dialog + if (confirm(`Are you sure you want to delete "${doc.title}"? This cannot be undone.`)) { + // Send delete request + fetch(`/api/document/${doc.id}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCsrfToken() + } + }) + .then(response => { + if (!response.ok) { + throw new Error('Failed to delete'); + } + return response.json(); + }) + .then(data => { + // Remove the document from the DOM + docLi.remove(); + + // Show notification + showNotification('Document deleted successfully'); + + // If we're on the document's page, redirect to the category or home + const currentPath = window.location.pathname; + if (currentPath === `/document/${doc.id}` || currentPath === `/document/${doc.id}/edit`) { + window.location.href = `/category/${category.id}`; + } + }) + .catch(error => { + console.error('Error:', error); + showNotification('Error deleting document', 'error'); + }); + } + }); + docActions.appendChild(deleteBtn); docLi.appendChild(docLink); docLi.appendChild(docActions); documentsUl.appendChild(docLi); }) - .catch(error => console.error('Error fetching document:', error)); + .catch(error => { + console.error(`Error fetching document ${docId}:`, error); + }); }); } @@ -477,10 +525,12 @@ } // Helper function to show notifications - function showNotification(message) { + function showNotification(message, type = 'success') { const notification = document.createElement('div'); - notification.className = 'fixed bottom-4 right-4 bg-primary/90 text-white px-4 py-2 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 flex items-center'; - notification.innerHTML = `${message}`; + const bgColor = type === 'success' ? 'bg-green-600' : 'bg-red-600'; + + notification.className = `fixed bottom-4 right-4 ${bgColor} text-white px-4 py-2 rounded-md shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 z-50`; + notification.textContent = message; document.body.appendChild(notification); @@ -490,7 +540,7 @@ }, 3000); } - // Helper function to get CSRF token from meta tag + // Helper function to get CSRF token function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]').getAttribute('content'); } @@ -589,5 +639,125 @@ {% block extra_js %}{% endblock %} + + +
+ + +