diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index a5f33dd98..dfc42343e 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -412,7 +412,9 @@ export interface ProjectListItem { target_count: number | null; created_at: string; archive_count: number; // Number of print jobs - total_items: number; // Sum of quantities (total items printed) + total_items: number; // Sum of quantities (total items printed, including failed) + completed_count: number; // Sum of quantities for completed prints only + failed_count: number; // Sum of quantities for failed prints queue_count: number; progress_percent: number | null; archives: ArchivePreview[]; diff --git a/frontend/src/pages/ProjectDetailPage.tsx b/frontend/src/pages/ProjectDetailPage.tsx index 8a94f84ba..1970dc7cb 100644 --- a/frontend/src/pages/ProjectDetailPage.tsx +++ b/frontend/src/pages/ProjectDetailPage.tsx @@ -79,18 +79,20 @@ function StatCard({ label, value, subValue, + hint, color = 'text-bambu-gray', }: { icon: React.ElementType; label: string; value: string | number; subValue?: string; + hint?: string; color?: string; }) { return ( -
+
@@ -435,9 +437,6 @@ export function ProjectDetailPage() { const stats = project.stats; const progressPercent = stats?.progress_percent ?? 0; - const successRate = stats && stats.total_items > 0 - ? ((stats.completed_prints / stats.total_items) * 100).toFixed(0) - : null; return (
@@ -486,7 +485,7 @@ export function ProjectDetailPage() {
Progress - {stats?.completed_prints || 0} / {project.target_count} items + {stats?.completed_prints || 0} / {project.target_count} completed
@@ -515,20 +514,25 @@ export function ProjectDetailPage() { {/* Stats grid */} {stats && (
- - 0 ? `${stats.failed_prints} failed` : (successRate ? `${successRate}% success` : undefined)} - color="text-blue-400" - /> + + +
+
+ +
+
+

Print Jobs

+

{stats.completed_prints} successful

+ {stats.failed_prints > 0 && ( +

{stats.failed_prints} failed

+ )} + {stats.total_archives - stats.completed_prints - stats.failed_prints > 0 && ( +

{stats.total_archives - stats.completed_prints - stats.failed_prints} in progress

+ )} +
+
+
+
- {project.total_items}/{project.target_count} items + {project.completed_count}/{project.target_count} completed - ) : project.total_items > 0 ? ( + ) : project.completed_count > 0 ? ( - {project.total_items} item{project.total_items !== 1 ? 's' : ''} + {project.completed_count} completed ) : null} {isCompleted && ( @@ -377,7 +377,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) {
Progress = 100 ? 'text-bambu-green font-medium' : 'text-white'}> - {project.total_items} / {project.target_count} + {project.completed_count} / {project.target_count}
@@ -392,16 +392,27 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) { }} />
-
- {progressPercent.toFixed(0)}% complete +
+ + {project.failed_count > 0 && `${project.failed_count} failed`} + + {progressPercent.toFixed(0)}% complete
- ) : project.total_items > 0 ? ( + ) : project.completed_count > 0 || project.failed_count > 0 ? (
-
- - {project.total_items} item{project.total_items !== 1 ? 's' : ''} completed -
+ {project.completed_count > 0 && ( +
+ + {project.completed_count} completed +
+ )} + {project.failed_count > 0 && ( +
+ + {project.failed_count} failed +
+ )} {project.queue_count > 0 && (
@@ -456,10 +467,16 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) { {/* Stats footer */}
-
- - {project.total_items} +
+ + {project.completed_count}
+ {project.failed_count > 0 && ( +
+ + {project.failed_count} +
+ )} {project.queue_count > 0 && (