mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 21:47:39 +02:00
* feat: print files directly from project view (closes #930) Show printable files from linked library folders directly in the project detail page, with Print Now and Add to Queue buttons per file. Removes the detour through the File Manager for common reprint workflows.
This commit is contained in:
@@ -1044,14 +1044,16 @@ async def scan_external_folder(
|
||||
async def list_files(
|
||||
response: Response,
|
||||
folder_id: int | None = None,
|
||||
project_id: int | None = None,
|
||||
include_root: bool = True,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_: User | None = Depends(require_permission_if_auth_enabled(Permission.LIBRARY_READ)),
|
||||
):
|
||||
"""List files, optionally filtered by folder.
|
||||
"""List files, optionally filtered by folder or project.
|
||||
|
||||
Args:
|
||||
folder_id: Filter by folder ID. If None and include_root=True, returns root files.
|
||||
project_id: Return all files across folders linked to this project (bulk fetch, avoids N+1).
|
||||
include_root: If True and folder_id is None, returns files at root level.
|
||||
If False and folder_id is None, returns all files.
|
||||
"""
|
||||
@@ -1059,6 +1061,10 @@ async def list_files(
|
||||
|
||||
if folder_id is not None:
|
||||
query = query.where(LibraryFile.folder_id == folder_id)
|
||||
elif project_id is not None:
|
||||
# Single join instead of one query per folder (avoids N+1 pattern)
|
||||
query = query.join(LibraryFolder, LibraryFile.folder_id == LibraryFolder.id)
|
||||
query = query.where(LibraryFolder.project_id == project_id)
|
||||
elif include_root:
|
||||
query = query.where(LibraryFile.folder_id.is_(None))
|
||||
|
||||
@@ -2210,6 +2216,12 @@ async def print_library_file(
|
||||
if not printer_manager.is_connected(printer_id):
|
||||
raise HTTPException(status_code=400, detail="Printer is not connected")
|
||||
|
||||
# Validate project exists before dispatching so a bogus ID yields 404, not a FK-constraint 500
|
||||
if body.project_id is not None:
|
||||
project_result = await db.execute(select(Project).where(Project.id == body.project_id))
|
||||
if not project_result.scalar_one_or_none():
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
plate_name = body.plate_name
|
||||
if not plate_name and body.plate_id is not None:
|
||||
plate_name = f"Plate {body.plate_id}"
|
||||
@@ -2225,6 +2237,7 @@ async def print_library_file(
|
||||
printer_id=printer_id,
|
||||
printer_name=printer.name,
|
||||
options=body.model_dump(exclude_none=True),
|
||||
project_id=body.project_id,
|
||||
requested_by_user_id=None,
|
||||
requested_by_username=None,
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@ from backend.app.models.library import LibraryFile
|
||||
from backend.app.models.print_batch import PrintBatch
|
||||
from backend.app.models.print_queue import PrintQueueItem
|
||||
from backend.app.models.printer import Printer
|
||||
from backend.app.models.project import Project
|
||||
from backend.app.models.user import User
|
||||
from backend.app.schemas.print_queue import (
|
||||
PrintBatchResponse,
|
||||
@@ -484,6 +485,12 @@ async def add_to_queue(
|
||||
if plate_time is not None:
|
||||
cached_print_time = plate_time
|
||||
|
||||
# Validate project exists before insert so a bogus ID yields 404, not an FK-constraint 500
|
||||
if data.project_id is not None:
|
||||
project_result = await db.execute(select(Project).where(Project.id == data.project_id))
|
||||
if not project_result.scalar_one_or_none():
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
ams_mapping_json = json.dumps(data.ams_mapping) if data.ams_mapping else None
|
||||
items = []
|
||||
for i in range(quantity):
|
||||
@@ -508,6 +515,7 @@ async def add_to_queue(
|
||||
timelapse=data.timelapse,
|
||||
use_ams=data.use_ams,
|
||||
gcode_injection=data.gcode_injection,
|
||||
project_id=data.project_id,
|
||||
position=max_pos + 1 + i,
|
||||
status="pending",
|
||||
created_by_id=current_user.id if current_user else None,
|
||||
|
||||
Reference in New Issue
Block a user