feat(mobile-fixes-phase4): Complete US-405 - Fix batchProgressStore - Restaurare Joburi Failed
Implemented by Ralph autonomous loop. Iteration: 4 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -104,8 +104,8 @@
|
|||||||
"unifiedItems computed include joburile failed pentru afișare",
|
"unifiedItems computed include joburile failed pentru afișare",
|
||||||
"npm run build passes"
|
"npm run build passes"
|
||||||
],
|
],
|
||||||
"passes": false,
|
"passes": true,
|
||||||
"notes": ""
|
"notes": "Completed in iteration 4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "US-406",
|
"id": "US-406",
|
||||||
|
|||||||
@@ -21,3 +21,9 @@ Stories: 8 (US-401 to US-408)
|
|||||||
[2026-01-12 19:23:21] Working on story: US-403
|
[2026-01-12 19:23:21] Working on story: US-403
|
||||||
[2026-01-12 19:23:21] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-403.log)
|
[2026-01-12 19:23:21] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_3_US-403.log)
|
||||||
[2026-01-12 19:27:05] SUCCESS: Story US-403 passed!
|
[2026-01-12 19:27:05] SUCCESS: Story US-403 passed!
|
||||||
|
[2026-01-12 19:27:05] Changes committed
|
||||||
|
[2026-01-12 19:27:05] Progress: 4/8 stories completed
|
||||||
|
[2026-01-12 19:27:07] === Iteration 4/50 ===
|
||||||
|
[2026-01-12 19:27:07] Working on story: US-405
|
||||||
|
[2026-01-12 19:27:07] Running Claude... (log: /workspace/roa2web/scripts/ralph/logs/iteration_4_US-405.log)
|
||||||
|
[2026-01-12 19:31:08] SUCCESS: Story US-405 passed!
|
||||||
|
|||||||
@@ -287,9 +287,13 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
console.log('[BatchProgress] All jobs finished, stopping polling')
|
console.log('[BatchProgress] All jobs finished, stopping polling')
|
||||||
isPolling.value = false
|
isPolling.value = false
|
||||||
|
|
||||||
// US-009: Remove completed batch from localStorage
|
// US-405: Only remove batch from localStorage if there are NO failed jobs
|
||||||
if (batchId.value) {
|
// Failed jobs need to persist so they're visible after refresh
|
||||||
|
if (batchId.value && data.failed_count === 0) {
|
||||||
|
console.log('[BatchProgress] No failed jobs, removing batch from storage')
|
||||||
removeActiveBatch(batchId.value)
|
removeActiveBatch(batchId.value)
|
||||||
|
} else if (data.failed_count > 0) {
|
||||||
|
console.log(`[BatchProgress] Batch has ${data.failed_count} failed jobs, keeping in storage for retry`)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -339,12 +343,46 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
* Clear a specific batch ID from localStorage.
|
* Clear a specific batch ID from localStorage.
|
||||||
* Called when a batch is determined to be complete (all items processed).
|
* Called when a batch is determined to be complete (all items processed).
|
||||||
*
|
*
|
||||||
|
* US-405: Can also be called when all failed jobs have been resolved
|
||||||
|
* (e.g., after successful retry or deletion of failed receipts).
|
||||||
|
*
|
||||||
* @param {string} batchIdToRemove - Batch ID to remove from storage
|
* @param {string} batchIdToRemove - Batch ID to remove from storage
|
||||||
*/
|
*/
|
||||||
function clearStoredBatch(batchIdToRemove) {
|
function clearStoredBatch(batchIdToRemove) {
|
||||||
removeActiveBatch(batchIdToRemove)
|
removeActiveBatch(batchIdToRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* US-405: Check if a batch should be cleared from storage.
|
||||||
|
* Returns true if the batch has no remaining failed jobs that need attention.
|
||||||
|
*
|
||||||
|
* Call this after retry or delete operations to clean up batches
|
||||||
|
* that no longer have failed jobs.
|
||||||
|
*/
|
||||||
|
function shouldClearBatch() {
|
||||||
|
// If no jobs remain, batch can be cleared
|
||||||
|
if (jobs.value.size === 0) return true
|
||||||
|
|
||||||
|
// If any jobs are still failed, keep the batch
|
||||||
|
for (const job of jobs.value.values()) {
|
||||||
|
if (job.status === 'failed') return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// No failed jobs remain
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* US-405: Clear batch from storage if no failed jobs remain.
|
||||||
|
* Call this after retry/delete operations to clean up localStorage.
|
||||||
|
*/
|
||||||
|
function clearBatchIfNoFailedJobs() {
|
||||||
|
if (shouldClearBatch() && batchId.value) {
|
||||||
|
console.log('[BatchProgress] No failed jobs remain, clearing batch from storage')
|
||||||
|
removeActiveBatch(batchId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all stored batch IDs from localStorage.
|
* Clear all stored batch IDs from localStorage.
|
||||||
* Used during cleanup or when all batches are confirmed complete.
|
* Used during cleanup or when all batches are confirmed complete.
|
||||||
@@ -365,12 +403,13 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore jobs from a stored batch by fetching current status from API.
|
* Restore jobs from a stored batch by fetching current status from API.
|
||||||
* Only pending/processing jobs are added to the store (completed/failed are already receipts).
|
* Restores pending, processing, AND failed jobs to the store.
|
||||||
*
|
*
|
||||||
* US-023: Called on page refresh/return to restore visibility of active jobs.
|
* US-023: Called on page refresh/return to restore visibility of active jobs.
|
||||||
|
* US-405: Now includes failed jobs so users can see OCR errors after refresh.
|
||||||
*
|
*
|
||||||
* @param {string} storedBatchId - The batch ID to restore from
|
* @param {string} storedBatchId - The batch ID to restore from
|
||||||
* @returns {Promise<{hasActiveJobs: boolean, jobCount: number}>} Result of restoration
|
* @returns {Promise<{hasActiveJobs: boolean, jobCount: number, hasFailedJobs: boolean}>} Result of restoration
|
||||||
*/
|
*/
|
||||||
async function restoreJobsFromBatch(storedBatchId) {
|
async function restoreJobsFromBatch(storedBatchId) {
|
||||||
try {
|
try {
|
||||||
@@ -387,26 +426,35 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
if (!data.jobs || data.jobs.length === 0) {
|
if (!data.jobs || data.jobs.length === 0) {
|
||||||
console.log(`[BatchProgress] Batch ${storedBatchId} has no jobs, removing from storage`)
|
console.log(`[BatchProgress] Batch ${storedBatchId} has no jobs, removing from storage`)
|
||||||
removeActiveBatch(storedBatchId)
|
removeActiveBatch(storedBatchId)
|
||||||
return { hasActiveJobs: false, jobCount: 0 }
|
return { hasActiveJobs: false, jobCount: 0, hasFailedJobs: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count and filter active jobs (pending/processing only)
|
// US-405: Include failed jobs in restoration (not just pending/processing)
|
||||||
|
// Failed jobs need to remain visible so users can see and resolve errors
|
||||||
|
const jobsToRestore = data.jobs.filter(
|
||||||
|
job => job.status === 'pending' || job.status === 'processing' || job.status === 'failed'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Count active jobs (pending/processing) for polling decision
|
||||||
const activeJobs = data.jobs.filter(
|
const activeJobs = data.jobs.filter(
|
||||||
job => job.status === 'pending' || job.status === 'processing'
|
job => job.status === 'pending' || job.status === 'processing'
|
||||||
)
|
)
|
||||||
|
|
||||||
if (activeJobs.length === 0) {
|
// Count failed jobs for return value
|
||||||
// All jobs are completed or failed - no need to restore to UI
|
const failedJobs = data.jobs.filter(job => job.status === 'failed')
|
||||||
console.log(`[BatchProgress] Batch ${storedBatchId} has no active jobs (all completed/failed), removing from storage`)
|
|
||||||
|
if (jobsToRestore.length === 0) {
|
||||||
|
// All jobs are completed - safe to remove batch from storage
|
||||||
|
console.log(`[BatchProgress] Batch ${storedBatchId} has no jobs to restore (all completed), removing from storage`)
|
||||||
removeActiveBatch(storedBatchId)
|
removeActiveBatch(storedBatchId)
|
||||||
return { hasActiveJobs: false, jobCount: 0 }
|
return { hasActiveJobs: false, jobCount: 0, hasFailedJobs: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set batch ID and add active jobs to store
|
// Set batch ID and add jobs to store
|
||||||
batchId.value = storedBatchId
|
batchId.value = storedBatchId
|
||||||
|
|
||||||
// Add jobs to the Map (merge with existing if any)
|
// Add jobs to the Map (merge with existing if any)
|
||||||
for (const job of activeJobs) {
|
for (const job of jobsToRestore) {
|
||||||
jobs.value.set(job.job_id, {
|
jobs.value.set(job.job_id, {
|
||||||
job_id: job.job_id,
|
job_id: job.job_id,
|
||||||
filename: job.filename,
|
filename: job.filename,
|
||||||
@@ -417,17 +465,22 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`[BatchProgress] Restored ${activeJobs.length} active jobs from batch ${storedBatchId}`)
|
console.log(`[BatchProgress] Restored ${jobsToRestore.length} jobs from batch ${storedBatchId} (${activeJobs.length} active, ${failedJobs.length} failed)`)
|
||||||
|
|
||||||
// Start polling for updates
|
// Only start polling if there are active jobs (pending/processing)
|
||||||
if (!isPolling.value) {
|
// Failed-only batches don't need polling - they're waiting for user action
|
||||||
|
if (activeJobs.length > 0 && !isPolling.value) {
|
||||||
isPolling.value = true
|
isPolling.value = true
|
||||||
abortController = new AbortController()
|
abortController = new AbortController()
|
||||||
// Start polling loop in background
|
// Start polling loop in background
|
||||||
pollLoop()
|
pollLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
return { hasActiveJobs: true, jobCount: activeJobs.length }
|
return {
|
||||||
|
hasActiveJobs: activeJobs.length > 0,
|
||||||
|
jobCount: jobsToRestore.length,
|
||||||
|
hasFailedJobs: failedJobs.length > 0
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[BatchProgress] Error restoring batch ${storedBatchId}:`, err)
|
console.error(`[BatchProgress] Error restoring batch ${storedBatchId}:`, err)
|
||||||
|
|
||||||
@@ -437,7 +490,7 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
removeActiveBatch(storedBatchId)
|
removeActiveBatch(storedBatchId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { hasActiveJobs: false, jobCount: 0 }
|
return { hasActiveJobs: false, jobCount: 0, hasFailedJobs: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,6 +631,10 @@ export const useBatchProgressStore = defineStore('batchProgress', () => {
|
|||||||
clearStoredBatch,
|
clearStoredBatch,
|
||||||
clearAllStoredBatches,
|
clearAllStoredBatches,
|
||||||
|
|
||||||
|
// US-405: Failed Jobs Cleanup
|
||||||
|
shouldClearBatch,
|
||||||
|
clearBatchIfNoFailedJobs,
|
||||||
|
|
||||||
// US-023: Restore Jobs from Batch
|
// US-023: Restore Jobs from Batch
|
||||||
restoreJobsFromBatch,
|
restoreJobsFromBatch,
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user