mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-01 11:47:46 +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.
195 lines
7.2 KiB
Python
195 lines
7.2 KiB
Python
from datetime import datetime
|
|
from typing import Annotated, Literal
|
|
|
|
from pydantic import BaseModel, PlainSerializer
|
|
|
|
|
|
# Custom serializer to ensure UTC datetimes have Z suffix
|
|
def serialize_utc_datetime(dt: datetime | None) -> str | None:
|
|
if dt is None:
|
|
return None
|
|
# Add Z suffix to indicate UTC
|
|
return dt.isoformat() + "Z"
|
|
|
|
|
|
UTCDatetime = Annotated[datetime | None, PlainSerializer(serialize_utc_datetime)]
|
|
|
|
|
|
class PrintQueueItemCreate(BaseModel):
|
|
printer_id: int | None = None # None = unassigned, user assigns later
|
|
target_model: str | None = None # Target printer model (mutually exclusive with printer_id)
|
|
target_location: str | None = None # Target location filter (only used with target_model)
|
|
required_filament_types: list[str] | None = None # Required filament types for model-based assignment
|
|
filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
|
|
# Either archive_id OR library_file_id must be provided
|
|
archive_id: int | None = None
|
|
library_file_id: int | None = None
|
|
scheduled_time: datetime | None = None # None = ASAP (next when idle)
|
|
require_previous_success: bool = False
|
|
auto_off_after: bool = False # Power off printer after print completes
|
|
manual_start: bool = False # Requires manual trigger to start (staged)
|
|
# AMS mapping: list of global tray IDs for each filament slot
|
|
# Format: [5, -1, 2, -1] where position = slot_id-1, value = global tray ID (-1 = unused)
|
|
ams_mapping: list[int] | None = None
|
|
# Plate ID for multi-plate 3MF files (1-indexed, None = auto-detect/plate 1)
|
|
plate_id: int | None = None
|
|
# Print options
|
|
bed_levelling: bool = True
|
|
flow_cali: bool = False
|
|
vibration_cali: bool = True
|
|
layer_inspect: bool = False
|
|
timelapse: bool = False
|
|
use_ams: bool = True
|
|
# Auto-print G-code injection
|
|
gcode_injection: bool = False
|
|
# Batch: create multiple copies (creates a batch if > 1)
|
|
quantity: int = 1
|
|
# Project to associate the resulting archive with
|
|
project_id: int | None = None
|
|
|
|
|
|
class PrintQueueItemUpdate(BaseModel):
|
|
printer_id: int | None = None
|
|
target_model: str | None = None # Target printer model (mutually exclusive with printer_id)
|
|
target_location: str | None = None # Target location filter (only used with target_model)
|
|
filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
|
|
position: int | None = None
|
|
scheduled_time: datetime | None = None
|
|
require_previous_success: bool | None = None
|
|
auto_off_after: bool | None = None
|
|
manual_start: bool | None = None
|
|
ams_mapping: list[int] | None = None
|
|
plate_id: int | None = None
|
|
# Print options
|
|
bed_levelling: bool | None = None
|
|
flow_cali: bool | None = None
|
|
vibration_cali: bool | None = None
|
|
layer_inspect: bool | None = None
|
|
timelapse: bool | None = None
|
|
use_ams: bool | None = None
|
|
# Auto-print G-code injection
|
|
gcode_injection: bool | None = None
|
|
|
|
|
|
class PrintQueueItemResponse(BaseModel):
|
|
id: int
|
|
printer_id: int | None # None = unassigned
|
|
target_model: str | None = None # Target printer model for model-based assignment
|
|
target_location: str | None = None # Target location filter for model-based assignment
|
|
required_filament_types: list[str] | None = None # Required filament types for model-based assignment
|
|
filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
|
|
waiting_reason: str | None = None # Why a model-based job hasn't started yet
|
|
archive_id: int | None # None if library_file_id is set (archive created at print start)
|
|
library_file_id: int | None # For queue items from library files
|
|
position: int
|
|
scheduled_time: UTCDatetime
|
|
require_previous_success: bool
|
|
auto_off_after: bool
|
|
manual_start: bool
|
|
ams_mapping: list[int] | None = None
|
|
plate_id: int | None = None # Plate ID for multi-plate 3MF files
|
|
# Print options
|
|
bed_levelling: bool = True
|
|
flow_cali: bool = False
|
|
vibration_cali: bool = True
|
|
layer_inspect: bool = False
|
|
timelapse: bool = False
|
|
use_ams: bool = True
|
|
status: Literal["pending", "printing", "completed", "failed", "skipped", "cancelled"]
|
|
started_at: UTCDatetime
|
|
completed_at: UTCDatetime
|
|
error_message: str | None
|
|
created_at: UTCDatetime
|
|
|
|
# Nested info for UI (populated in route)
|
|
archive_name: str | None = None
|
|
archive_thumbnail: str | None = None
|
|
library_file_name: str | None = None # Name of library file (if library_file_id is set)
|
|
library_file_thumbnail: str | None = None # Thumbnail of library file
|
|
printer_name: str | None = None
|
|
print_time_seconds: int | None = None # Estimated print time from archive or library file
|
|
filament_used_grams: float | None = None # Estimated print weight from archive or library file
|
|
filament_type: str | None = None # e.g. "PLA", "PETG" (from archive/library file)
|
|
filament_color: str | None = None # e.g. "#FFFFFF" (from archive/library file)
|
|
layer_height: float | None = None # e.g. 0.2 (from archive/library file)
|
|
nozzle_diameter: float | None = None # e.g. 0.4 (from archive/library file)
|
|
sliced_for_model: str | None = None # e.g. "P1S" (from archive/library file)
|
|
|
|
# User tracking (Issue #206)
|
|
created_by_id: int | None = None
|
|
created_by_username: str | None = None
|
|
|
|
# Batch grouping
|
|
batch_id: int | None = None
|
|
batch_name: str | None = None
|
|
|
|
# Shortest-job-first scheduling
|
|
been_jumped: bool = False
|
|
|
|
# Auto-print G-code injection
|
|
gcode_injection: bool = False
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class PrintQueueReorderItem(BaseModel):
|
|
id: int
|
|
position: int
|
|
|
|
|
|
class PrintQueueReorder(BaseModel):
|
|
items: list[PrintQueueReorderItem]
|
|
|
|
|
|
class PrintQueueBulkUpdate(BaseModel):
|
|
"""Bulk update multiple queue items with the same values."""
|
|
|
|
item_ids: list[int]
|
|
# Fields to update (all optional - only set fields are applied)
|
|
printer_id: int | None = None
|
|
scheduled_time: datetime | None = None
|
|
require_previous_success: bool | None = None
|
|
auto_off_after: bool | None = None
|
|
manual_start: bool | None = None
|
|
# Print options
|
|
bed_levelling: bool | None = None
|
|
flow_cali: bool | None = None
|
|
vibration_cali: bool | None = None
|
|
layer_inspect: bool | None = None
|
|
timelapse: bool | None = None
|
|
use_ams: bool | None = None
|
|
# Auto-print G-code injection
|
|
gcode_injection: bool | None = None
|
|
|
|
|
|
class PrintQueueBulkUpdateResponse(BaseModel):
|
|
"""Response for bulk update operation."""
|
|
|
|
updated_count: int
|
|
skipped_count: int # Items that were not pending
|
|
message: str
|
|
|
|
|
|
class PrintBatchResponse(BaseModel):
|
|
"""Response for a print batch with progress stats."""
|
|
|
|
id: int
|
|
name: str
|
|
archive_id: int | None = None
|
|
library_file_id: int | None = None
|
|
quantity: int
|
|
status: str
|
|
created_at: UTCDatetime
|
|
created_by_id: int | None = None
|
|
created_by_username: str | None = None
|
|
# Derived counts
|
|
pending_count: int = 0
|
|
printing_count: int = 0
|
|
completed_count: int = 0
|
|
failed_count: int = 0
|
|
cancelled_count: int = 0
|
|
|
|
class Config:
|
|
from_attributes = True
|