Add project parts tracking separate from plates

Track individual parts/objects separately from print plates in projects.
Useful for multi-part builds like Voron where 25 plates produce 150 parts.

Backend:
- Add target_parts_count field to Project model
- Calculate parts_progress_percent and remaining_parts in stats
- Auto-detect quantity from 3MF printable objects when archiving
- Sum archive quantities for completed_count (parts)
- Use archive_count for plates progress

Frontend:
- Add "Target Parts" input in project create/edit modal
- Show separate progress bars for plates vs parts
- Stats footer displays both plates and parts count
- Header badge shows parts progress when target set

Scripts:
- Add update_archive_quantities.py to migrate existing archives

Tests:
- Add 5 integration tests for parts tracking
- Add 3 unit tests for 3MF object extraction

Closes #85
This commit is contained in:
maziggy
2026-01-16 07:33:44 +01:00
parent c514e1f2af
commit 693466eafc
15 changed files with 805 additions and 239 deletions
+14 -8
View File
@@ -341,17 +341,19 @@ export interface SimilarArchive {
export interface ProjectStats {
total_archives: number;
total_items: number; // Sum of quantities (total items printed)
completed_prints: number;
completed_prints: number; // Sum of quantities for completed prints (parts)
failed_prints: number;
queued_prints: number;
in_progress_prints: number;
total_print_time_hours: number;
total_filament_grams: number;
progress_percent: number | null;
progress_percent: number | null; // Plates progress (total_archives / target_count)
parts_progress_percent: number | null; // Parts progress (completed_prints / target_parts_count)
estimated_cost: number;
total_energy_kwh: number;
total_energy_cost: number;
remaining_prints: number | null;
remaining_prints: number | null; // Remaining plates
remaining_parts: number | null; // Remaining parts
bom_total_items: number;
bom_completed_items: number;
}
@@ -370,7 +372,8 @@ export interface Project {
description: string | null;
color: string | null;
status: string; // active, completed, archived
target_count: number | null;
target_count: number | null; // Target number of plates/print jobs
target_parts_count: number | null; // Target number of parts/objects
notes: string | null;
attachments: ProjectAttachment[] | null;
tags: string | null;
@@ -409,14 +412,15 @@ export interface ProjectListItem {
description: string | null;
color: string | null;
status: string;
target_count: number | null;
target_count: number | null; // Target number of plates/print jobs
target_parts_count: number | null; // Target number of parts/objects
created_at: string;
archive_count: number; // Number of print jobs
archive_count: number; // Number of print jobs (plates)
total_items: number; // Sum of quantities (total items printed, including failed)
completed_count: number; // Sum of quantities for completed prints only
completed_count: number; // Sum of quantities for completed prints only (parts)
failed_count: number; // Sum of quantities for failed prints
queue_count: number;
progress_percent: number | null;
progress_percent: number | null; // Plates progress
archives: ArchivePreview[];
}
@@ -425,6 +429,7 @@ export interface ProjectCreate {
description?: string;
color?: string;
target_count?: number;
target_parts_count?: number;
notes?: string;
tags?: string;
due_date?: string;
@@ -439,6 +444,7 @@ export interface ProjectUpdate {
color?: string;
status?: string;
target_count?: number;
target_parts_count?: number;
notes?: string;
tags?: string;
due_date?: string;