Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add OCR and sync logging overviews to settings - #67

Merged
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview
Jul 2, 2026
Merged

Add OCR and sync logging overviews to settings#67
maxi07 merged 11 commits into
mainfrom
copilot/add-logging-overview

Conversation

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Only file naming jobs were surfaced in the web UI; OCR and sync (upload) jobs had no visibility. This adds OCR and Sync log tables mirroring the existing File Naming logs.

Persistence

  • sync_jobs table added to schema.sql; the pre-existing but unused ocr_jobs table is now populated.
  • ocr_service writes a PROCESSING row on start and finalizes with status + a human-readable error on every completion/failure branch.
  • upload_service records the sync lifecycle (including missing-OCR-file and upload-failure paths) with a success flag and error description; ProcessItem gains sync_db_id.

API

  • New GET /api/ocr-logs and GET /api/sync-logs, paginated and filterable (all/success/failed), via a shared _fetch_job_logs helper. Table/filter fragments are hardcoded constants; only pagination values are bound parameters.

Frontend

  • OCR Logs accordion in the OCR tab; Sync Logs accordion in the OneDrive tab.
  • The per-table logs JS is consolidated into a reusable createLogsTable factory (own pagination/filter state, lazy-load on expand) driving all three tables:
createLogsTable({endpoint: '/api/ocr-logs',collapseId: 'ocr-logsCollapse',tableId: 'ocr-logs-table',/* ... */renderRow: (log)=>`<tr><td>${log.id}</td><td>${getStatusBadge(log.ocr_status)}</td>...</tr>`});
  • Full file-name/error text is shown via a data-fulltext attribute + addEventListener rather than inline onclick string interpolation, avoiding injection from unescaped backslashes.

Tests

  • tests/test_logs_api.py covers pagination, filters, null-count handling, and error responses for both endpoints.

Note: the click-to-expand uses alert() for parity with the existing File Naming table; a more accessible modal is left as a potential follow-up.

CopilotAI linked an issue Jul 2, 2026 that may be closed by this pull request
CopilotAI changed the title [WIP] Add logging overview for sync and OCR processesAdd OCR and sync logging overviews to settingsJul 2, 2026
CopilotAI requested a review from maxi07July 2, 2026 07:54
@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 14:59

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds end-to-end visibility for OCR and OneDrive sync (upload) job activity in the Settings UI, bringing those services to parity with the existing File Naming logs by persisting job lifecycle data, exposing new paginated API endpoints, and rendering new log tables in the frontend.

Changes:

  • Added persistence for OCR and Sync job lifecycles (ocr_jobs population + new sync_jobs table) from ocr_service and upload_service.
  • Added new paginated/filterable API endpoints (/api/ocr-logs, /api/sync-logs) using a shared _fetch_job_logs helper.
  • Extended the Settings UI with OCR and Sync log accordions and refactored frontend log rendering into a reusable createLogsTable factory.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
web_service/src/templates/settings-tab/settings-tab-onedrive.htmlAdds a Sync Logs accordion/table to the OneDrive settings tab.
web_service/src/templates/settings-tab/settings-tab-ocr.htmlReplaces placeholder OCR text with an OCR Logs accordion/table.
web_service/src/static/js/settings.jsIntroduces createLogsTable/initLogTables and shared rendering helpers for all log tables.
web_service/src/routes/api.pyAdds _fetch_job_logs plus new /api/ocr-logs and /api/sync-logs endpoints.
upload_service/main.pyInserts/updates sync_jobs records across the upload lifecycle.
tests/test_logs_api.pyAdds API tests for OCR/sync logs pagination and filtering.
scansynclib/scansynclib/ProcessItem.pyAdds sync_db_id field to ProcessItem.
scansynclib/scansynclib/db/schema.sqlAdds the new sync_jobs table schema.
ocr_service/main.pyInserts ocr_jobs rows at start and finalizes status/error on completion/failure.

Comment threadweb_service/src/routes/api.py Outdated
Comment on lines +277 to +281
page = int(request.args.get('page', 1))
per_page = int(request.args.get('per_page', 20))
filter = request.args.get('filter', 'all').lower()
offset = (page - 1) * per_page

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. Both params are now parsed inside try/except (ValueError, TypeError) blocks with safe defaults. page is clamped to max(1, ...) with no upper limit, and per_page is clamped to max(1, min(100, ...)) to prevent zero/negative values and unbounded queries.

Comment threadupload_service/main.py Outdated
Comment on lines +48 to +51
logger.exception(f"Failed processing {body}.")
item.status = ProcessStatus.SYNC_FAILED
update_scanneddata_database(item, {"file_status": item.status.value})
finalize_sync_job(item, "Unexpected error during upload")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. item is now initialized to None before the try block. The except clause checks item is not None and isinstance(item, ProcessItem) before updating status/DB, and additionally checks item.sync_db_id is not None before calling finalize_sync_job.

Comment on lines +16 to +34
# Mock Redis before any scansynclib imports, since settings.py connects at module level
import redis as _real_redis
_orig_from_url = _real_redis.Redis.from_url


def _mock_from_url(*args, **kwargs):
mock_client = MagicMock()
mock_client.get.return_value = None # No existing settings in Redis
mock_client.set.return_value = True
mock_client.publish.return_value = 0
mock_pubsub = MagicMock()
mock_pubsub.subscribe.return_value = None
mock_pubsub.listen.return_value = iter([]) # Empty iterator
mock_client.pubsub.return_value = mock_pubsub
return mock_client


_real_redis.Redis.from_url = _mock_from_url

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in the latest commit. The module-level assignment and the unused _orig_from_url have been removed. The patch is now applied and torn down in a @pytest.fixture(scope="session", autouse=True) fixture that saves the original, yields, and restores it—preventing any leak into other test modules.

@maxi07

Copy link
Copy Markdown
Owner

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descriptions for the OCR failures once and make them reusable, so we can display the message also to the user in the web instead of creating new error messages in the js file with getOcrStatusText.

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot I dont like your addition of the our status text within a JS file and the except blocks within ocr_service/main.py. Please, similar to the ProcessItem definition, define all the error descrip...

Done. Here's what changed:

  1. scansynclib/ProcessItem.pyOCRStatus now follows the same pattern as FileNamingStatus: each member's .value is its human-readable description (e.g. DPI_ERROR = "Image DPI too low for accurate OCR").

  2. ocr_service/main.py – All ad-hoc string literals in except blocks are replaced with OCRStatus.<STATUS>.value, with exception detail appended where available (e.g. f"{OCRStatus.DPI_ERROR.value}: {dpiex}").

  3. web_service/src/routes/api.py – The /api/ocr-logs response enriches each log entry with ocr_status_text = OCRStatus[status_name].value, so the frontend receives the server-defined description directly.

  4. settings.jsgetStatusBadge accepts an optional displayText parameter; the OCR logs row passes log.ocr_status_text so the badge uses the Python-defined text instead of a JS toTitleCase conversion.

@maxi07
maxi07 requested a review from CopilotJuly 2, 2026 16:08
@maxi07
maxi07 marked this pull request as ready for review July 2, 2026 16:12

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment threadocr_service/main.py
Comment threadscansynclib/scansynclib.egg-info/SOURCES.txt Outdated
maxi07and others added 2 commits July 2, 2026 18:13
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>
@maxi07

Copy link
Copy Markdown
Owner

@copilot resolve the merge conflicts in this pull request

CopilotAI commented Jul 2, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot resolve the merge conflicts in this pull request

Done. Merged origin/main into this branch in commit e126ae6. The only conflicts were in scansynclib/ProcessItem.py and ocr_service/main.py:

  • ProcessItem.py: Kept our string enum values for OCRStatus and added the new NO_TEXT = "No text found in OCR output" member from main.
  • ocr_service/main.py: Used main's refined structure (result=None init, if item.ocr_db_id guard, OCRStatus.NO_TEXT for the no-text-found path) and removed the duplicate DB INSERT/ocr_error declarations left by the conflict markers. Error strings match the existing test expectations in test_ocr_job_tracking.py.

@maxi07
maxi07 merged commit 512ca42 into mainJul 2, 2026
4 checks passed
@maxi07
maxi07 deleted the copilot/add-logging-overview branch July 2, 2026 17:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a logging overview

3 participants

@maxi07