feat: Implement collection deletion and loading spinners
- Add API endpoint and handler to delete collections - Introduce LoadingSpinner component for async operations - Show loading spinners during file loading and preview rendering - Enhance modal accessibility by removing aria-hidden attribute - Refactor delete functionality to distinguish between collections and files/folders - Remove unused collection definitions from config
This commit is contained in:
		| @@ -104,6 +104,10 @@ class MarkdownEditorApp: | ||||
|         if path == '/fs/' and method == 'POST': | ||||
|             return self.handle_create_collection(environ, start_response) | ||||
|  | ||||
|         # API to delete a collection | ||||
|         if path.startswith('/api/collections/') and method == 'DELETE': | ||||
|             return self.handle_delete_collection(environ, start_response) | ||||
|  | ||||
|         # Check if path starts with a collection name (for SPA routing) | ||||
|         # This handles URLs like /notes/ttt or /documents/file.md | ||||
|         # MUST be checked BEFORE WebDAV routing to prevent WebDAV from intercepting SPA routes | ||||
| @@ -205,7 +209,68 @@ class MarkdownEditorApp: | ||||
|             print(f"Error creating collection: {e}") | ||||
|             start_response('500 Internal Server Error', [('Content-Type', 'application/json')]) | ||||
|             return [json.dumps({'error': str(e)}).encode('utf-8')] | ||||
|      | ||||
|  | ||||
|     def handle_delete_collection(self, environ, start_response): | ||||
|         """Delete a collection""" | ||||
|         try: | ||||
|             # Extract collection name from path: /api/collections/{name} | ||||
|             path = environ.get('PATH_INFO', '') | ||||
|             collection_name = path.split('/')[-1] | ||||
|  | ||||
|             if not collection_name: | ||||
|                 start_response('400 Bad Request', [('Content-Type', 'application/json')]) | ||||
|                 return [json.dumps({'error': 'Collection name is required'}).encode('utf-8')] | ||||
|  | ||||
|             # Check if collection exists | ||||
|             if collection_name not in self.collections: | ||||
|                 start_response('404 Not Found', [('Content-Type', 'application/json')]) | ||||
|                 return [json.dumps({'error': f'Collection "{collection_name}" not found'}).encode('utf-8')] | ||||
|  | ||||
|             # Get collection path | ||||
|             collection_config = self.collections[collection_name] | ||||
|             collection_path = Path(collection_config['path']) | ||||
|  | ||||
|             # Delete the collection directory and all its contents | ||||
|             import shutil | ||||
|             if collection_path.exists(): | ||||
|                 shutil.rmtree(collection_path) | ||||
|                 print(f"Deleted collection directory: {collection_path}") | ||||
|  | ||||
|             # Remove from collections dict | ||||
|             del self.collections[collection_name] | ||||
|  | ||||
|             # Update config file | ||||
|             self.save_config() | ||||
|  | ||||
|             # Remove from WebDAV provider mapping | ||||
|             provider_key = f'/fs/{collection_name}' | ||||
|             if hasattr(self.webdav_app, 'provider_map') and provider_key in self.webdav_app.provider_map: | ||||
|                 del self.webdav_app.provider_map[provider_key] | ||||
|                 print(f"Removed provider from provider_map: {provider_key}") | ||||
|  | ||||
|             # Remove from sorted_share_list if it exists | ||||
|             if hasattr(self.webdav_app, 'sorted_share_list') and provider_key in self.webdav_app.sorted_share_list: | ||||
|                 self.webdav_app.sorted_share_list.remove(provider_key) | ||||
|                 print(f"Removed from sorted_share_list: {provider_key}") | ||||
|  | ||||
|             print(f"Deleted collection '{collection_name}'") | ||||
|  | ||||
|             response_body = json.dumps({'success': True, 'name': collection_name}).encode('utf-8') | ||||
|             start_response('200 OK', [ | ||||
|                 ('Content-Type', 'application/json'), | ||||
|                 ('Content-Length', str(len(response_body))), | ||||
|                 ('Access-Control-Allow-Origin', '*') | ||||
|             ]) | ||||
|  | ||||
|             return [response_body] | ||||
|  | ||||
|         except Exception as e: | ||||
|             print(f"Error deleting collection: {e}") | ||||
|             import traceback | ||||
|             traceback.print_exc() | ||||
|             start_response('500 Internal Server Error', [('Content-Type', 'application/json')]) | ||||
|             return [json.dumps({'error': str(e)}).encode('utf-8')] | ||||
|  | ||||
|     def handle_static(self, environ, start_response): | ||||
|         """Serve static files""" | ||||
|         path = environ.get('PATH_INFO', '')[1:]  # Remove leading / | ||||
|   | ||||
		Reference in New Issue
	
	Block a user