From 4e25377e5b809c7717cae41766f5e1d050a686b3 Mon Sep 17 00:00:00 2001 From: maziggy Date: Fri, 2 Jan 2026 10:17:21 +0100 Subject: [PATCH] Updated website --- frontend/src/api/client.ts | 6 ++++- frontend/src/components/EditArchiveModal.tsx | 23 +++++++++++++++++++- frontend/src/pages/ProjectDetailPage.tsx | 15 +++++++------ frontend/src/pages/ProjectsPage.tsx | 16 +++++++------- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 83ab6a0cb..24789a101 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -223,6 +223,7 @@ export interface Archive { cost: number | null; photos: string[] | null; failure_reason: string | null; + quantity: number; energy_kwh: number | null; energy_cost: number | null; created_at: string; @@ -333,6 +334,7 @@ export interface SimilarArchive { // Project types export interface ProjectStats { total_archives: number; + total_items: number; // Sum of quantities (total items printed) completed_prints: number; failed_prints: number; queued_prints: number; @@ -403,7 +405,8 @@ export interface ProjectListItem { status: string; target_count: number | null; created_at: string; - archive_count: number; + archive_count: number; // Number of print jobs + total_items: number; // Sum of quantities (total items printed) queue_count: number; progress_percent: number | null; archives: ArchivePreview[]; @@ -1407,6 +1410,7 @@ export const api = { cost?: number; failure_reason?: string | null; status?: string; + quantity?: number; }) => request(`/archives/${id}`, { method: 'PATCH', diff --git a/frontend/src/components/EditArchiveModal.tsx b/frontend/src/components/EditArchiveModal.tsx index fdab477a8..620a57212 100644 --- a/frontend/src/components/EditArchiveModal.tsx +++ b/frontend/src/components/EditArchiveModal.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from 'react'; import { useMutation, useQueryClient, useQuery } from '@tanstack/react-query'; -import { X, Save, Tag, Camera, Trash2, Loader2, Plus, FolderKanban } from 'lucide-react'; +import { X, Save, Tag, Camera, Trash2, Loader2, Plus, FolderKanban, Hash } from 'lucide-react'; import { api } from '../api/client'; import type { Archive } from '../api/client'; import { Button } from './Button'; @@ -49,6 +49,7 @@ export function EditArchiveModal({ archive, onClose, existingTags = [] }: EditAr const [tags, setTags] = useState(archive.tags || ''); const [failureReason, setFailureReason] = useState(archive.failure_reason || ''); const [status, setStatus] = useState(archive.status); + const [quantity, setQuantity] = useState(archive.quantity ?? 1); const [photos, setPhotos] = useState(archive.photos || []); const [uploadingPhoto, setUploadingPhoto] = useState(false); const [showTagSuggestions, setShowTagSuggestions] = useState(false); @@ -153,6 +154,7 @@ export function EditArchiveModal({ archive, onClose, existingTags = [] }: EditAr project_id: projectId, notes: notes || undefined, tags: tags || undefined, + quantity: quantity, }; // Only include status if changed @@ -242,6 +244,25 @@ export function EditArchiveModal({ archive, onClose, existingTags = [] }: EditAr + {/* Quantity - number of items printed */} +
+ + setQuantity(Math.max(1, parseInt(e.target.value) || 1))} + className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none" + placeholder="1" + /> +

+ Number of items produced in this print job +

+
+ {/* Notes */}
diff --git a/frontend/src/pages/ProjectDetailPage.tsx b/frontend/src/pages/ProjectDetailPage.tsx index c97b41594..77c44161c 100644 --- a/frontend/src/pages/ProjectDetailPage.tsx +++ b/frontend/src/pages/ProjectDetailPage.tsx @@ -434,8 +434,8 @@ export function ProjectDetailPage() { const stats = project.stats; const progressPercent = stats?.progress_percent ?? 0; - const successRate = stats && stats.total_archives > 0 - ? ((stats.completed_prints / stats.total_archives) * 100).toFixed(0) + const successRate = stats && stats.total_items > 0 + ? ((stats.completed_prints / stats.total_items) * 100).toFixed(0) : null; return ( @@ -485,7 +485,7 @@ export function ProjectDetailPage() {
Progress - {stats?.completed_prints || 0} / {project.target_count} prints + {stats?.completed_prints || 0} / {project.target_count} items
@@ -516,16 +516,16 @@ export function ProjectDetailPage() {
0 ? `${stats.failed_prints} failed` : undefined} + subValue={stats.failed_prints > 0 ? `${stats.failed_prints} failed` : (successRate ? `${successRate}% success` : undefined)} color="text-blue-400" /> - {project.archive_count}/{project.target_count} parts + {project.total_items}/{project.target_count} items - ) : project.archive_count > 0 ? ( + ) : project.total_items > 0 ? ( - {project.archive_count} print{project.archive_count !== 1 ? 's' : ''} + {project.total_items} item{project.total_items !== 1 ? 's' : ''} ) : null} {isCompleted && ( @@ -365,7 +365,7 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) {
Progress = 100 ? 'text-bambu-green font-medium' : 'text-white'}> - {project.archive_count} / {project.target_count} + {project.total_items} / {project.target_count}
@@ -384,11 +384,11 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) { {progressPercent.toFixed(0)}% complete
- ) : project.archive_count > 0 ? ( + ) : project.total_items > 0 ? (
- {project.archive_count} print{project.archive_count !== 1 ? 's' : ''} completed + {project.total_items} item{project.total_items !== 1 ? 's' : ''} completed
{project.queue_count > 0 && (
@@ -444,9 +444,9 @@ function ProjectCard({ project, onClick, onEdit, onDelete }: ProjectCardProps) { {/* Stats footer */}
-
+
- {project.archive_count} + {project.total_items}
{project.queue_count > 0 && (