From 4fd8ad284fa5edef5a8e580c9c6edad0c5f4afb0 Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Thu, 26 Mar 2026 12:26:05 +0100 Subject: [PATCH] fix: Improve step control UX and fix machine error display - Consolidate progress stats into 3 cards (stitches, time, speed) - Keep rollback info visible after machine clears error while paused - Remove Resume/Start Sewing buttons in STOP state (error must be resolved on machine first) - Use adjustedStitchIndex for progress display to prevent desync - Make step control layout stable (always render all buttons) - Reduce polling interval from 500ms to 1000ms during sewing - Fix machine errors (e.g. HoopError) not showing in error badge when there was no accompanying string error message Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/AppHeader.tsx | 8 +- .../ProgressMonitor/ProgressMonitor.tsx | 21 ++--- .../ProgressMonitor/ProgressSection.tsx | 33 +------ .../ProgressMonitor/ProgressStats.tsx | 18 ++-- .../ProgressMonitor/StitchStepControl.tsx | 92 +++++++++---------- src/stores/useMachineStore.ts | 13 +-- src/utils/machineStateHelpers.ts | 17 ++-- 7 files changed, 85 insertions(+), 117 deletions(-) diff --git a/src/components/AppHeader.tsx b/src/components/AppHeader.tsx index 51af7f1..a234581 100644 --- a/src/components/AppHeader.tsx +++ b/src/components/AppHeader.tsx @@ -187,7 +187,9 @@ export function AppHeader() { + )} + - - {/* Navigation buttons */} -
- {colorBlocks.length > 0 && ( - - )} - {pausedStitchIndex !== null && displayStitch !== pausedStitchIndex && ( - - )} +
); diff --git a/src/stores/useMachineStore.ts b/src/stores/useMachineStore.ts index 8dfbc17..de9faa3 100644 --- a/src/stores/useMachineStore.ts +++ b/src/stores/useMachineStore.ts @@ -487,13 +487,8 @@ export const useMachineStore = create((set, get) => ({ }); } } - // Reset rollback tracking when error clears while still paused - else if ( - currentState.lastRolledBackError !== null && - currentState.machineError === SewingMachineError.None - ) { - set({ lastRolledBackError: null }); - } + // Note: we intentionally do NOT clear lastRolledBackError when the error clears + // while still paused, so the rollback info text remains visible to the user. // Auto-rollback for thread errors when machine is interrupted or paused mid-sew // Only runs once on entering paused state (when pausedStitchIndex is not yet set) @@ -508,9 +503,7 @@ export const useMachineStore = create((set, get) => ({ // Snapshot the paused position (after rollback, before manual adjustments) const postRollbackStitch = - get().adjustedStitchIndex ?? - get().sewingProgress?.currentStitch ?? - 0; + get().adjustedStitchIndex ?? get().sewingProgress?.currentStitch ?? 0; set({ pausedStitchIndex: postRollbackStitch }); } diff --git a/src/utils/machineStateHelpers.ts b/src/utils/machineStateHelpers.ts index a933281..fc57c5b 100644 --- a/src/utils/machineStateHelpers.ts +++ b/src/utils/machineStateHelpers.ts @@ -97,10 +97,8 @@ export function canUploadPattern(status: MachineStatus): boolean { export function canStartSewing(status: MachineStatus): boolean { // Only in specific ready states return ( - status === MachineStatus.SEWING_WAIT || status === MachineStatus.MASK_TRACE_COMPLETE || status === MachineStatus.PAUSE || - status === MachineStatus.STOP || status === MachineStatus.SEWING_INTERRUPTION ); } @@ -114,7 +112,10 @@ export function canStartMaskTrace( status: MachineStatus, hasSewingProgress = false, ): boolean { - if (status === MachineStatus.IDLE || status === MachineStatus.MASK_TRACE_COMPLETE) { + if ( + status === MachineStatus.IDLE || + status === MachineStatus.MASK_TRACE_COMPLETE + ) { return true; } // Only allow mask trace in SEWING_WAIT if sewing hasn't started yet @@ -126,12 +127,14 @@ export function canStartMaskTrace( /** * Determines if sewing can be resumed in the current state. - * Only for interrupted operations (PAUSE, STOP, SEWING_INTERRUPTION). + * Only for PAUSE and SEWING_INTERRUPTION - not STOP, which requires + * the user to resolve the error on the machine first. */ export function canResumeSewing(status: MachineStatus): boolean { - // Only in interrupted states - const category = getMachineStateCategory(status); - return category === MachineStateCategory.INTERRUPTED; + return ( + status === MachineStatus.PAUSE || + status === MachineStatus.SEWING_INTERRUPTION + ); } /**