Repository navigation
Improve progress bar with per-step success/failure tracking, marquee animation, and tooltips - #56
Conversation
- Current step shows blue marquee animation - Completed steps turn green - Failed/deleted files show all segments red - Mouse-over tooltips show step name and status - Five steps: File Detection, Reading Metadata, OCR, File Naming, Upload Agent-Logs-Url: https://github.com/maxi07/ScanSync/sessions/bd124723-e8f5-41b8-87b4-706c4b54a319 Co-authored-by: maxi07 <7480270+maxi07@users.noreply.github.com>
|
@copilot the web interface actually needs to reflect the success of each individual failure. meaning, we need to read from js variables such as |
- Add ocr_status and file_naming_status to SSE payload (main.py) - Join ocr_jobs and file_naming_jobs in dashboard query for static data - Add getStepStatuses() to determine individual step success/failure - Completed steps show green, failed individual steps show red - Detection/metadata/upload failure derived from file_status - OCR and file naming failure derived from their specific status fields Agent-Logs-Url: https://github.com/maxi07/ScanSync/sessions/5266926b-1101-4d90-9c4f-018674b32880 Co-authored-by: maxi07 <7480270+maxi07@users.noreply.github.com>
Implemented per-step success/failure tracking in commit Backend changes:
Frontend changes:
|
There was a problem hiding this comment.
Pull request overview
This PR enhances the web dashboard’s segmented progress bar to reflect per-step outcomes (completed/current/pending/failed), adds an animated “current step” marquee effect, and surfaces step/status tooltips using OCR and file-naming job status data from live SSE updates and the dashboard query.
Changes:
- Updated
dashboard.jsto compute per-step visual states (completed/current/pending/failed) usingfile_status,ocr_status, andfile_naming_status, and to apply new segment classes and tooltips. - Updated
dashboard.cssto add.completed(green) and.current(animated gradient) styling plus hover tooltip rendering. - Updated the dashboard backend to include
ocr_status/file_naming_statusin both initial page data (SQL joins) and live SSE payloads.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| web_service/src/static/js/dashboard.js | Adds per-step status computation and updates progress bar rendering/classes/tooltips for initial cards and SSE updates. |
| web_service/src/static/css/dashboard.css | Adds new segment styles (completed/current animation) and hover tooltip styling; allows overflow for tooltip display. |
| web_service/src/routes/dashboard.py | Extends dashboard query to include latest OCR and file-naming job status values per scanned item. |
| web_service/src/main.py | Adds ocr_status and file_naming_status fields to SSE payloads for live updates. |
| @@ -452,19 +452,28 @@ function addPdfCard(pdfData) { | |||
| progressContainer.id = pdfData.id + '_progress_bar'; | |||
|
|
|||
| const progressStep = pdfData.status_progressbar || 1; | |||
| LEFT JOIN ( | ||
| SELECT scanneddata_id, ocr_status | ||
| FROM ocr_jobs | ||
| WHERE id IN (SELECT MAX(id) FROM ocr_jobs GROUP BY scanneddata_id) | ||
| ) ocr ON d.id = ocr.scanneddata_id |
| .progress-segment[title]:hover::after { | ||
| content: attr(title); | ||
| position: absolute; | ||
| bottom: calc(100% + 6px); | ||
| left: 50%; | ||
| transform: translateX(-50%); | ||
| background-color: rgba(0, 0, 0, 0.85); | ||
| color: #fff; | ||
| padding: 4px 8px; | ||
| border-radius: 4px; | ||
| font-size: 0.7rem; | ||
| white-space: nowrap; | ||
| z-index: 10; | ||
| pointer-events: none; | ||
| } |
|
@copilot add ui tests that validate the changed from this pr description have actually been implemented. please use the playwright browser to test the new behavior, also making sure that every step is represented correctly. also add corner cases with different failure reasons |
Implemented in |
| return Array.from( | ||
| document.querySelectorAll(`#${pdfData.id}_progress_bar .progress-segment`) | ||
| ).map((segment) => ({ | ||
| classes: Array.from(segment.classList), | ||
| tooltip: segment.getAttribute('data-tooltip'), | ||
| ariaLabel: segment.getAttribute('aria-label'), | ||
| })); |
| const parsedProgressStep = Number(pdfData.status_progressbar); | ||
| const progressStep = Number.isFinite(parsedProgressStep) ? parsedProgressStep : 1; | ||
| const isDeleted = pdfData.file_status?.toLowerCase().includes("deleted"); | ||
| const isFailed = pdfData.file_status?.toLowerCase().includes("failed") || isDeleted || pdfData.status_progressbar === -1; | ||
| const isCompleted = pdfData.file_status?.toLowerCase().includes("completed"); |
| ocr_status=item.ocr_status.name if getattr(item, "ocr_status", None) else None, | ||
| file_naming_status=item.file_naming_status.name if getattr(item, "file_naming_status", None) else None, |
| segment.classList.remove('active', 'failed', 'completed', 'current'); | ||
|
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
file_naming_service/main.py:93
- The generic exception handler can raise a new exception when
itemis None or not a ProcessItem (e.g., ifpickle.loads(body)fails). Referencingitem.filename(and unconditionally updatingfile_naming_jobsusingitem.file_naming_db_id) will crash the callback and prevent the RabbitMQ message from being acked.
except Exception as e:
logger.exception(f"Failed processing {item.filename}.")
execute_query("UPDATE file_naming_jobs SET file_naming_status = ?, error_description = ?, finished = DATETIME('now', 'localtime') WHERE id = ?", (FileNamingStatus.FAILED.name, str(e), item.file_naming_db_id))
| LEFT JOIN ( | ||
| SELECT scanneddata_id, ocr_status | ||
| FROM ocr_jobs | ||
| WHERE id IN (SELECT MAX(id) FROM ocr_jobs GROUP BY scanneddata_id) | ||
| ) ocr ON d.id = ocr.scanneddata_id |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| .progress-segment { | ||
| flex: 1; | ||
| background-color: #dee2e6; | ||
| transition: background-color 0.3s; | ||
| border-radius: 2px; |
| .progress-segment.failed { | ||
| background-color: #dc3545; /* Bootstrap-Rot */ | ||
| background-color: #dc3545; | ||
| } | ||
|
|
||
| .progress-segment.completed { | ||
| background-color: green; /* Bootstrap-Rot */ | ||
| .progress-segment.pending { |
|
@copilot resolve the merge conflicts in this pull request |
Merge conflicts resolved in the merge commit
|
….com/maxi07/ScanSync into copilot/utilize-progress-bar-on-card
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
file_naming_service/main.py:93
- The generic
except Exceptionhandler assumesitemis a validProcessItemand accessesitem.filename/item.file_naming_db_id. If deserialization fails (or any exception happens beforeitemis assigned), this handler will raise a secondaryAttributeError, masking the original error and potentially crashing the consumer loop.
except Exception as e:
logger.exception(f"Failed processing {item.filename}.")
execute_query("UPDATE file_naming_jobs SET file_naming_status = ?, error_description = ?, finished = DATETIME('now', 'localtime') WHERE id = ?", (FileNamingStatus.FAILED.name, str(e), item.file_naming_db_id))
| LEFT JOIN file_naming_jobs fn | ||
| ON fn.id = ( | ||
| SELECT MAX(id) | ||
| FROM file_naming_jobs | ||
| WHERE scanneddata_id = d.id | ||
| ) |
| "scripts": { | ||
| "test": "echo \"Error: no test specified\" && exit 1" | ||
| "test": "echo \"Error: no test specified\" && exit 1", | ||
| "test:js": "node --test \"tests/js/**/*.test.mjs\"" | ||
| }, |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Progress bar segments now visually distinguish between completed, in-progress, and pending steps. Current step shows a blue marquee animation, completed steps turn green, and individual failed steps turn red. Each segment has a hover tooltip showing step name and status. Per-step success/failure is determined using
ocr_status,file_naming_status, andfile_statusdata.CSS (
dashboard.css).activeclass with.completed(green#198754) and.current(animated blue gradient)@keyframes marqueefor the shimmer effect on the active segment::afterpseudo-element tooltip on hover.progress-bar-wrappertooverflow: visibleso tooltips render above the barBackend (
main.py,dashboard.py)ocr_statusandfile_naming_statusto the SSE payload for live updatesocr_jobsandfile_naming_jobstables in the dashboard query to include per-step status in static page dataJS (
dashboard.js)getStepStatuses()helper determines each step's visual state using per-step status data:file_statusis "Invalid File"ocr_statusindicates failure (FAILED, UNSUPPORTED, DPI_ERROR, INPUT_ERROR, OUTPUT_ERROR)file_naming_statusindicates failure (FAILED, NO_OCR_FILE, NO_PDF_TEXT, NO_SERVER_CONNECTION, etc.)file_statusis "Sync Failed"addPdfCard()andupdateProgressBar()usegetStepStatuses()for consistent renderingdata-tooltip+aria-labeltooltip/status label (e.g."OCR – Failed","File Naming – Completed")Step labels map to the five processing stages: File Detection → Reading Metadata → OCR → File Naming → Upload
Tests (
tests/test_homepage.py)INPUT_ERROR)NO_SERVER_CONNECTION)Sync Failed)UNSUPPORTED)