feat: Add browse folder API and enhance folder selection in Scan component
This commit introduces a new API endpoint for browsing folders, utilizing tkinter for a native folder picker dialog. The Scan component has been updated to integrate this functionality, allowing users to select folders more easily. If the native picker is unavailable, a browser-based fallback is implemented, ensuring a seamless user experience. Additionally, the input field for batch size has been modified to restrict input to numeric values only, improving data validation. Documentation has been updated to reflect these changes.
This commit is contained in:
@@ -313,6 +313,75 @@ async def upload_photos(
|
||||
}
|
||||
|
||||
|
||||
@router.post("/browse-folder")
|
||||
def browse_folder() -> dict:
|
||||
"""Open native folder picker dialog and return selected folder path.
|
||||
|
||||
Uses tkinter to show a native OS folder picker dialog.
|
||||
Returns the full absolute path of the selected folder.
|
||||
|
||||
Returns:
|
||||
dict with 'path' (str) and 'success' (bool) keys
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import tkinter as tk
|
||||
from tkinter import filedialog
|
||||
except ImportError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="tkinter is not available. Cannot show folder picker.",
|
||||
)
|
||||
|
||||
try:
|
||||
# Create root window (hidden)
|
||||
root = tk.Tk()
|
||||
root.withdraw() # Hide main window
|
||||
root.attributes('-topmost', True) # Bring to front
|
||||
|
||||
# Show folder picker dialog
|
||||
folder_path = filedialog.askdirectory(
|
||||
title="Select folder to scan",
|
||||
mustexist=True
|
||||
)
|
||||
|
||||
# Clean up
|
||||
root.destroy()
|
||||
|
||||
if folder_path:
|
||||
# Normalize path to absolute
|
||||
abs_path = os.path.abspath(folder_path)
|
||||
return {
|
||||
"path": abs_path,
|
||||
"success": True,
|
||||
"message": f"Selected folder: {abs_path}"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"path": "",
|
||||
"success": False,
|
||||
"message": "No folder selected"
|
||||
}
|
||||
except Exception as e:
|
||||
# Handle errors gracefully
|
||||
error_msg = str(e)
|
||||
|
||||
# Check for common issues (display/headless server)
|
||||
if "display" in error_msg.lower() or "DISPLAY" not in os.environ:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="No display available. Cannot show folder picker. "
|
||||
"If running on a remote server, ensure X11 forwarding is enabled.",
|
||||
)
|
||||
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Error showing folder picker: {error_msg}",
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{photo_id}", response_model=PhotoResponse)
|
||||
def get_photo(photo_id: int, db: Session = Depends(get_db)) -> PhotoResponse:
|
||||
"""Get photo by ID."""
|
||||
|
||||
Reference in New Issue
Block a user