diff --git a/application/single_app/config.py b/application/single_app/config.py index ee1bc63d..d5ba49b6 100644 --- a/application/single_app/config.py +++ b/application/single_app/config.py @@ -88,7 +88,7 @@ EXECUTOR_TYPE = 'thread' EXECUTOR_MAX_WORKERS = 30 SESSION_TYPE = 'filesystem' -VERSION = "0.237.009" +VERSION = "0.237.011" SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production') diff --git a/application/single_app/route_frontend_chats.py b/application/single_app/route_frontend_chats.py index 8e34c0f4..a7f8e6a0 100644 --- a/application/single_app/route_frontend_chats.py +++ b/application/single_app/route_frontend_chats.py @@ -118,7 +118,8 @@ def upload_file(): file.seek(0) filename = secure_filename(file.filename) - file_ext = os.path.splitext(filename)[1].lower() + file_ext = os.path.splitext(filename)[1].lower() # e.g., '.png' + file_ext_nodot = file_ext.lstrip('.') # e.g., 'png' with tempfile.NamedTemporaryFile(delete=False) as tmp_file: file.save(tmp_file.name) @@ -131,9 +132,9 @@ def upload_file(): try: # Check if this is an image file - is_image_file = file_ext in IMAGE_EXTENSIONS + is_image_file = file_ext_nodot in IMAGE_EXTENSIONS - if file_ext in ['.pdf', '.docx', '.pptx', '.ppt', '.html'] or is_image_file: + if file_ext_nodot in (DOCUMENT_EXTENSIONS | {'html'}) or is_image_file: extracted_content_raw = extract_content_with_azure_di(temp_file_path) # Convert pages_data list to string @@ -191,25 +192,25 @@ def upload_file(): print(f"Warning: Vision analysis failed for chat upload: {vision_error}") # Continue without vision analysis - elif file_ext in ['.doc', '.docm']: + elif file_ext_nodot in {'doc', 'docm'}: # Use docx2txt for .doc and .docm files try: import docx2txt extracted_content = docx2txt.process(temp_file_path) except ImportError: return jsonify({'error': 'docx2txt library required for .doc/.docm files'}), 500 - elif file_ext == '.txt': + elif file_ext_nodot == 'txt': extracted_content = extract_text_file(temp_file_path) - elif file_ext == '.md': + elif file_ext_nodot == 'md': extracted_content = extract_markdown_file(temp_file_path) - elif file_ext == '.json': + elif file_ext_nodot == 'json': with open(temp_file_path, 'r', encoding='utf-8') as f: parsed_json = json.load(f) extracted_content = json.dumps(parsed_json, indent=2) - elif file_ext in ['.xml', '.yaml', '.yml', '.log']: + elif file_ext_nodot in {'xml', 'yaml', 'yml', 'log'}: # Handle XML, YAML, and LOG files as text for inline chat extracted_content = extract_text_file(temp_file_path) - elif file_ext in TABULAR_EXTENSIONS: + elif file_ext_nodot in TABULAR_EXTENSIONS: extracted_content = extract_table_file(temp_file_path, file_ext) is_table = True else: diff --git a/application/single_app/static/js/group/manage_group.js b/application/single_app/static/js/group/manage_group.js index a6b00cc4..d6372838 100644 --- a/application/single_app/static/js/group/manage_group.js +++ b/application/single_app/static/js/group/manage_group.js @@ -92,39 +92,6 @@ $(document).ready(function () { rejectRequest(requestId); }); - // Add event delegation for select user button in search results - $(document).on("click", ".select-user-btn", function () { - const id = $(this).data("user-id"); - const name = $(this).data("user-name"); - const email = $(this).data("user-email"); - selectUserForAdd(id, name, email); - }); - - // Add event delegation for remove member button - $(document).on("click", ".remove-member-btn", function () { - const userId = $(this).data("user-id"); - removeMember(userId); - }); - - // Add event delegation for change role button - $(document).on("click", ".change-role-btn", function () { - const userId = $(this).data("user-id"); - const currentRole = $(this).data("user-role"); - openChangeRoleModal(userId, currentRole); - $("#changeRoleModal").modal("show"); - }); - - // Add event delegation for approve/reject request buttons - $(document).on("click", ".approve-request-btn", function () { - const requestId = $(this).data("request-id"); - approveRequest(requestId); - }); - - $(document).on("click", ".reject-request-btn", function () { - const requestId = $(this).data("request-id"); - rejectRequest(requestId); - }); - // CSV Bulk Upload Events $("#addBulkMemberBtn").on("click", function () { $("#csvBulkUploadModal").modal("show"); @@ -504,11 +471,21 @@ function setRole(userId, newRole) { data: JSON.stringify({ role: newRole }), success: function () { $("#changeRoleModal").modal("hide"); + showToast("success", "Role updated successfully"); loadMembers(); }, error: function (err) { - console.error(err); - alert("Failed to update role."); + console.error("Error updating role:", err); + let errorMsg = "Failed to update role."; + if (err.status === 404) { + errorMsg = "Member not found. They may have been removed."; + loadMembers(); // Refresh the member list + } else if (err.status === 403) { + errorMsg = "You don't have permission to change this member's role."; + } else if (err.responseJSON && err.responseJSON.message) { + errorMsg = err.responseJSON.message; + } + showToast("error", errorMsg); }, }); } @@ -519,11 +496,21 @@ function removeMember(userId) { url: `/api/groups/${groupId}/members/${userId}`, method: "DELETE", success: function () { + showToast("success", "Member removed successfully"); loadMembers(); }, error: function (err) { - console.error(err); - alert("Failed to remove member."); + console.error("Error removing member:", err); + let errorMsg = "Failed to remove member."; + if (err.status === 404) { + errorMsg = "Member not found. They may have already been removed."; + loadMembers(); // Refresh the member list + } else if (err.status === 403) { + errorMsg = "You don't have permission to remove this member."; + } else if (err.responseJSON && err.responseJSON.message) { + errorMsg = err.responseJSON.message; + } + showToast("error", errorMsg); }, }); } @@ -631,7 +618,6 @@ function searchUsers() { }); } -// Render user-search results in add-member modal // Render user-search results in add-member modal function renderUserSearchResults(users) { let html = ""; diff --git a/docs/explanation/release_notes.md b/docs/explanation/release_notes.md index 384d44bc..2b002285 100644 --- a/docs/explanation/release_notes.md +++ b/docs/explanation/release_notes.md @@ -2,6 +2,26 @@ # Feature Release +### **(v0.237.011)** + +#### Bug Fixes + +* **Chat File Upload "Unsupported File Type" Fix** + * Fixed issue where uploading xlsx, png, jpg, csv, and other image/tabular files in the chat interface returned a 400 "Unsupported file type" error. + * **Root Cause**: `os.path.splitext()` returns extensions with a leading dot (e.g., `.png`), but the `IMAGE_EXTENSIONS` and `TABULAR_EXTENSIONS` sets in `config.py` store extensions without dots (e.g., `png`). The comparison `'.png' in {'png', ...}` was always `False`, causing all image and tabular uploads to fall through to the unsupported file type error. + * **Solution**: Added `file_ext_nodot = file_ext.lstrip('.')` and used the dot-stripped extension for set comparisons against `IMAGE_EXTENSIONS` and `TABULAR_EXTENSIONS`, matching the pattern already used in `functions_documents.py`. + * (Ref: `route_frontend_chats.py`, file extension comparison, `IMAGE_EXTENSIONS`, `TABULAR_EXTENSIONS`) + +* **Manage Group Page Duplicate Code and Error Handling Fix** + * Fixed multiple code quality and user experience issues in the Manage Group page JavaScript. + * **Duplicate Event Handlers**: Removed duplicate event handler registrations (lines 96-127) for `.select-user-btn`, `.remove-member-btn`, `.change-role-btn`, `.approve-request-btn`, and `.reject-request-btn` that were causing multiple event firings. + * **Duplicate HTML in Actions Column**: Fixed member action buttons rendering duplicate attributes as visible text instead of functional buttons, causing raw HTML/CSS class names to display in the Actions column. + * **Duplicate Pending Request Buttons**: Removed duplicate Approve and Reject buttons in pending requests table that were appearing twice per request. + * **Enhanced Error Handling**: Improved `setRole()` and `removeMember()` functions with specific error messages for 404 (member not found) and 403 (permission denied) errors, automatic member list refresh on 404, and user-friendly toast notifications instead of generic alerts. + * **Removed Duplicate Comment**: Cleaned up duplicate "Render user-search results" comment. + * **Impact**: Member management buttons now render and function correctly, provide better error feedback, and auto-recover from stale member data. + * (Ref: `manage_group.js`, event handler deduplication, error handling improvements, toast notifications) + ### **(v0.237.009)** #### New Features