Przeglądaj źródła

- Add rename functionality for files and folders:
- New RenameModal component with validation
- Backend endpoint supports filename updates (rejects path separators)
- Context menu "Rename" option in grid and list views
- Inline rename button in list view actions
- Add Print button to multi-selection toolbar:
- Appears when exactly one sliced file is selected
- Opens full PrintModal with plate selection and options
- Add to Queue button now uses Clock icon for clarity
- Improve mobile/PWA accessibility:
- Three-dot menu button always visible on mobile (md:opacity-0)
- Selection checkbox always visible on touch devices
- Better experience for PWA users on tablets and phones

Closes #94

maziggy 4 miesięcy temu
rodzic
commit
d32059ab78

+ 12 - 0
CHANGELOG.md

@@ -58,6 +58,18 @@ All notable changes to Bambuddy will be documented in this file.
   - "Embedded": Shows camera as a floating overlay on the main screen
   - Embedded viewer is draggable and resizable with persistent position/size
   - Configure in Settings → General → Camera section
+- **File Manager Rename** - Rename files and folders directly in File Manager:
+  - Right-click context menu "Rename" option for files and folders
+  - Inline rename button in list view
+  - Validates filenames (no path separators allowed)
+- **File Manager Print Button** - Print directly from multi-selection toolbar:
+  - "Print" button appears when exactly one sliced file is selected
+  - Opens full PrintModal with plate selection and print options
+  - "Add to Queue" button now uses Clock icon for clarity
+- **File Manager Mobile Accessibility** - Improved touch device support:
+  - Three-dot menu button always visible on mobile (hover-only on desktop)
+  - Selection checkbox always visible on mobile devices
+  - Better PWA experience for file management
 
 ### Changed
 - **Edit Queue Item modal** - Single printer selection only (reassigns item, doesn't duplicate)

+ 2 - 0
README.md

@@ -82,10 +82,12 @@
 ### 📁 File Manager (Library)
 - Upload and organize sliced files (3MF, gcode)
 - Folder structure with drag-and-drop
+- Rename files and folders via context menu
 - Print directly to any printer with full options
 - Add to queue without creating archive upfront
 - Plate selection for multi-plate 3MF files
 - Duplicate detection via file hash
+- Mobile-friendly with always-visible action buttons
 
 ### 📁 Projects
 - Group related prints (e.g., "Voron Build")

+ 6 - 0
backend/app/api/routes/library.py

@@ -1406,6 +1406,12 @@ async def update_file(file_id: int, data: FileUpdate, db: AsyncSession = Depends
     if not file:
         raise HTTPException(status_code=404, detail="File not found")
 
+    if data.filename is not None:
+        # Validate filename doesn't contain path separators
+        if "/" in data.filename or "\\" in data.filename:
+            raise HTTPException(status_code=400, detail="Filename cannot contain path separators")
+        file.filename = data.filename
+
     if data.folder_id is not None:
         if data.folder_id == 0:
             file.folder_id = None

+ 1 - 0
backend/app/schemas/library.py

@@ -80,6 +80,7 @@ class FileCreate(BaseModel):
 class FileUpdate(BaseModel):
     """Schema for updating a file."""
 
+    filename: str | None = Field(None, min_length=1, max_length=255)
     folder_id: int | None = None
     project_id: int | None = None
     notes: str | None = None

+ 31 - 0
backend/tests/integration/test_library_api.py

@@ -204,6 +204,37 @@ class TestLibraryFilesAPI:
         result = response.json()
         assert result.get("message") or result.get("success", True)
 
+    @pytest.mark.asyncio
+    @pytest.mark.integration
+    async def test_rename_file(self, async_client: AsyncClient, file_factory, db_session):
+        """Verify file can be renamed."""
+        lib_file = await file_factory(filename="old_name.3mf")
+        data = {"filename": "new_name.3mf"}
+        response = await async_client.put(f"/api/v1/library/files/{lib_file.id}", json=data)
+        assert response.status_code == 200
+        result = response.json()
+        assert result["filename"] == "new_name.3mf"
+
+    @pytest.mark.asyncio
+    @pytest.mark.integration
+    async def test_rename_file_invalid_path_separator(self, async_client: AsyncClient, file_factory, db_session):
+        """Verify file rename fails with path separators."""
+        lib_file = await file_factory(filename="test.3mf")
+        data = {"filename": "path/to/file.3mf"}
+        response = await async_client.put(f"/api/v1/library/files/{lib_file.id}", json=data)
+        assert response.status_code == 400
+        assert "path separator" in response.json()["detail"].lower()
+
+    @pytest.mark.asyncio
+    @pytest.mark.integration
+    async def test_rename_file_invalid_backslash(self, async_client: AsyncClient, file_factory, db_session):
+        """Verify file rename fails with backslash."""
+        lib_file = await file_factory(filename="test.3mf")
+        data = {"filename": "path\\to\\file.3mf"}
+        response = await async_client.put(f"/api/v1/library/files/{lib_file.id}", json=data)
+        assert response.status_code == 400
+        assert "path separator" in response.json()["detail"].lower()
+
     @pytest.mark.asyncio
     @pytest.mark.integration
     async def test_library_stats(self, async_client: AsyncClient, folder_factory, file_factory, db_session):

Plik diff jest za duży
+ 0 - 0
static/assets/index-BL-2WI3B.js


Plik diff jest za duży
+ 0 - 0
static/assets/index-BmODu1qm.css


+ 2 - 2
static/index.html

@@ -23,8 +23,8 @@
 
     <!-- Splash screens for iOS -->
     <link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
-    <script type="module" crossorigin src="/assets/index-Cw4dIiLT.js"></script>
-    <link rel="stylesheet" crossorigin href="/assets/index-C__bvgqz.css">
+    <script type="module" crossorigin src="/assets/index-BL-2WI3B.js"></script>
+    <link rel="stylesheet" crossorigin href="/assets/index-BmODu1qm.css">
   </head>
   <body>
     <div id="root"></div>

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików