feat(ui): add ARIA attributes for accessibility improvements

Add aria-hidden="true" to decorative Font Awesome icons across templates,
aria-label to icon-only buttons, aria-live to dynamic content regions,
aria-labelledby to modals, aria-expanded to toggle buttons, scope="col"
to table headers, and aria-label to tables. Also improve alt text on
500.html error image and add aria-label to password toggle buttons.

Templates updated: settings.html, credentials.html, status_dashboard.html,
file_view.html, file_detail.html, index.html, queue_dashboard.html,
audit_log.html, 500.html

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-28 16:04:33 +00:00
parent bf6bbe3512
commit 0969436abd
9 changed files with 122 additions and 113 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
<div class="mx-auto max-w-3xl py-12">
<img
src="/static/explosion.jpg"
alt="Server Explosion"
alt="Illustration of a server error"
class="mx-auto rounded-xl shadow-xl h-[300px] w-full object-cover"
/>
</div>
+11 -11
View File
@@ -14,7 +14,7 @@
</div>
<a href="/settings"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
<i class="fas fa-cog mr-2"></i> Back to Settings
<i class="fas fa-cog mr-2" aria-hidden="true"></i> Back to Settings
</a>
</div>
@@ -29,16 +29,16 @@
{% if entries %}
<div class="bg-white shadow rounded-lg overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<table class="min-w-full divide-y divide-gray-200" aria-label="Settings audit log">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">When</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Changed By</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Setting Key</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Old Value</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">New Value</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Rollback</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">When</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Changed By</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Setting Key</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Action</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Old Value</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">New Value</th>
<th scope="col" class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Rollback</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
@@ -78,7 +78,7 @@
class="inline-flex items-center px-2 py-1 text-xs font-medium rounded border border-gray-300 text-gray-700 bg-white hover:bg-yellow-50 hover:border-yellow-400 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-yellow-400 disabled:opacity-50 disabled:cursor-not-allowed"
title="Revert '{{ entry.key }}' to the value in this log entry"
>
<span x-show="rollingBack !== {{ entry.id }}"><i class="fas fa-undo mr-1"></i>Rollback</span>
<span x-show="rollingBack !== {{ entry.id }}"><i class="fas fa-undo mr-1" aria-hidden="true"></i>Rollback</span>
<span x-show="rollingBack === {{ entry.id }}">Working…</span>
</button>
</td>
@@ -89,7 +89,7 @@
</div>
{% else %}
<div class="bg-white shadow rounded-lg p-8 text-center text-gray-500">
<i class="fas fa-history text-4xl mb-4 block text-gray-300"></i>
<i class="fas fa-history text-4xl mb-4 block text-gray-300" aria-hidden="true"></i>
<p class="text-lg">No configuration changes recorded yet.</p>
<p class="text-sm mt-2">Changes you make on the <a href="/settings" class="text-blue-600 hover:underline">Settings page</a> will appear here.</p>
</div>
+14 -13
View File
@@ -7,7 +7,7 @@
<!-- Page Header -->
<div class="mb-8">
<div class="flex items-center gap-3 mb-2">
<i class="fas fa-key text-yellow-500 text-2xl"></i>
<i class="fas fa-key text-yellow-500 text-2xl" aria-hidden="true"></i>
<h1 class="text-3xl font-bold">Credential Audit</h1>
</div>
<p class="text-gray-600">
@@ -20,7 +20,7 @@
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-8">
<div class="bg-white rounded-lg shadow p-5 flex items-center gap-4">
<span class="inline-flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 text-blue-600 text-xl">
<i class="fas fa-list"></i>
<i class="fas fa-list" aria-hidden="true"></i>
</span>
<div>
<div class="text-2xl font-bold text-gray-800">{{ total }}</div>
@@ -29,7 +29,7 @@
</div>
<div class="bg-white rounded-lg shadow p-5 flex items-center gap-4">
<span class="inline-flex items-center justify-center h-12 w-12 rounded-full bg-green-100 text-green-600 text-xl">
<i class="fas fa-check-circle"></i>
<i class="fas fa-check-circle" aria-hidden="true"></i>
</span>
<div>
<div class="text-2xl font-bold text-green-700">{{ configured_count }}</div>
@@ -38,7 +38,7 @@
</div>
<div class="bg-white rounded-lg shadow p-5 flex items-center gap-4">
<span class="inline-flex items-center justify-center h-12 w-12 rounded-full bg-gray-100 text-gray-500 text-xl">
<i class="fas fa-circle-question"></i>
<i class="fas fa-circle-question" aria-hidden="true"></i>
</span>
<div>
<div class="text-2xl font-bold text-gray-600">{{ unconfigured_count }}</div>
@@ -49,7 +49,7 @@
<!-- Legend -->
<div class="bg-blue-50 border-l-4 border-blue-500 text-blue-800 p-4 mb-6 rounded-r-md">
<p class="font-semibold mb-2"><i class="fas fa-circle-info mr-1"></i> Legend</p>
<p class="font-semibold mb-2"><i class="fas fa-circle-info mr-1" aria-hidden="true"></i> Legend</p>
<div class="flex flex-wrap gap-4 text-sm">
<span>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800 mr-1">DB</span>
@@ -85,7 +85,7 @@
<!-- Credentials Table -->
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<table class="min-w-full divide-y divide-gray-200" aria-label="Credentials for {{ category }}">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-56">
@@ -130,11 +130,11 @@
<td class="px-6 py-4 whitespace-nowrap">
{% if cred.configured %}
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold bg-green-100 text-green-800">
<i class="fas fa-check mr-1"></i> Configured
<i class="fas fa-check mr-1" aria-hidden="true"></i> Configured
</span>
{% else %}
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold bg-red-100 text-red-700">
<i class="fas fa-circle-exclamation mr-1"></i> Missing
<i class="fas fa-circle-exclamation mr-1" aria-hidden="true"></i> Missing
</span>
{% endif %}
</td>
@@ -143,11 +143,11 @@
<td class="px-6 py-4 whitespace-nowrap">
{% if cred.source == 'db' %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800" title="Stored in database (encrypted)">
<i class="fas fa-database mr-1 text-xs"></i> DB
<i class="fas fa-database mr-1 text-xs" aria-hidden="true"></i> DB
</span>
{% elif cred.source == 'env' %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800" title="From environment variable">
<i class="fas fa-terminal mr-1 text-xs"></i> ENV
<i class="fas fa-terminal mr-1 text-xs" aria-hidden="true"></i> ENV
</span>
{% else %}
<span class="text-gray-400 text-xs"></span>
@@ -158,9 +158,10 @@
<td class="px-6 py-4 whitespace-nowrap text-center">
<a href="/settings#{{ cred.key }}"
title="Edit in Settings"
aria-label="Edit {{ cred.key }}"
class="inline-flex items-center justify-center w-7 h-7 rounded text-gray-400 hover:text-blue-600 hover:bg-blue-50 transition-colors"
>
<i class="fas fa-pen-to-square text-sm"></i>
<i class="fas fa-pen-to-square text-sm" aria-hidden="true"></i>
</a>
</td>
@@ -177,13 +178,13 @@
<a href="/settings"
class="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm font-medium"
>
<i class="fas fa-cog"></i> Manage Settings
<i class="fas fa-cog" aria-hidden="true"></i> Manage Settings
</a>
<a href="/api/settings/credentials"
target="_blank"
class="inline-flex items-center gap-2 px-4 py-2 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 text-sm font-medium"
>
<i class="fas fa-code"></i> Raw JSON (API)
<i class="fas fa-code" aria-hidden="true"></i> Raw JSON (API)
</a>
</div>
+25 -21
View File
@@ -958,8 +958,8 @@
{% block content %}
<div class="detail-container">
<a href="/files" class="back-button">
<i class="fas fa-arrow-left"></i>
<a href="/files" class="back-button" aria-label="Back to File List">
<i class="fas fa-arrow-left" aria-hidden="true"></i>
Back to File List
</a>
@@ -979,15 +979,15 @@
{% set main_completed = step_summary.main.success + step_summary.main.skipped %}
{% set uploads_completed = step_summary.uploads.success + step_summary.uploads.skipped %}
{% if file.is_duplicate %}
<i class="fas fa-copy" style="color: #6b7280; margin-right: 0.5rem;"></i>Duplicate
<i class="fas fa-copy" aria-hidden="true" style="color: #6b7280; margin-right: 0.5rem;"></i>Duplicate
{% elif step_summary.main.failure > 0 or step_summary.uploads.failure > 0 %}
<i class="fas fa-times-circle" style="color: #dc2626; margin-right: 0.5rem;"></i>Failed
<i class="fas fa-times-circle" aria-hidden="true" style="color: #dc2626; margin-right: 0.5rem;"></i>Failed
{% elif step_summary.main["in_progress"] > 0 or step_summary.uploads["in_progress"] > 0 %}
<i class="fas fa-circle-notch" style="color: #f59e0b; margin-right: 0.5rem; animation: spin 1s linear infinite;"></i>Processing
<i class="fas fa-circle-notch" aria-hidden="true" style="color: #f59e0b; margin-right: 0.5rem; animation: spin 1s linear infinite;"></i>Processing
{% elif step_summary.total_main_steps > 0 and main_completed == step_summary.total_main_steps and step_summary.main.failure == 0 %}
<i class="fas fa-check-circle" style="color: #059669; margin-right: 0.5rem;"></i>Completed
<i class="fas fa-check-circle" aria-hidden="true" style="color: #059669; margin-right: 0.5rem;"></i>Completed
{% else %}
<i class="fas fa-pause-circle" style="color: #f59e0b; margin-right: 0.5rem;"></i>Pending
<i class="fas fa-pause-circle" aria-hidden="true" style="color: #f59e0b; margin-right: 0.5rem;"></i>Pending
{% endif %}
</div>
</div>
@@ -1066,11 +1066,11 @@
<span class="detail-value">
{% if original_file_exists %}
<span class="file-status-indicator exists">
<i class="fas fa-check-circle"></i> File exists
<i class="fas fa-check-circle" aria-hidden="true"></i> File exists
</span>
{% else %}
<span class="file-status-indicator missing">
<i class="fas fa-times-circle"></i> File not found
<i class="fas fa-times-circle" aria-hidden="true"></i> File not found
</span>
{% endif %}
</span>
@@ -1086,11 +1086,11 @@
<span class="detail-value">
{% if processed_file_exists %}
<span class="file-status-indicator exists">
<i class="fas fa-check-circle"></i> File exists
<i class="fas fa-check-circle" aria-hidden="true"></i> File exists
</span>
{% else %}
<span class="file-status-indicator missing">
<i class="fas fa-times-circle"></i> File not found
<i class="fas fa-times-circle" aria-hidden="true"></i> File not found
</span>
{% endif %}
</span>
@@ -1196,7 +1196,7 @@
</div>
<div class="pdf-canvas-wrapper" id="original-canvas-wrapper">
<div class="pdf-loading">
<i class="fas fa-spinner fa-spin" style="font-size: 2rem; margin-bottom: 1rem;"></i>
<i class="fas fa-spinner fa-spin" aria-hidden="true" style="font-size: 2rem; margin-bottom: 1rem;"></i>
<p>Loading PDF...</p>
</div>
</div>
@@ -1205,11 +1205,11 @@
onclick="loadAndShowText('original', {{ file.id }})"
style="margin-top: 0.5rem; background-color: #4299e1; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600; width: 100%;"
>
<i class="fas fa-file-alt"></i> View Extracted Text
<i class="fas fa-file-alt" aria-hidden="true"></i> View Extracted Text
</button>
{% else %}
<div style="text-align: center; padding: 3rem; background-color: #f7fafc; border-radius: 0.5rem; color: #718096;">
<i class="fas fa-file-pdf" style="font-size: 3rem; opacity: 0.5; margin-bottom: 1rem;"></i>
<i class="fas fa-file-pdf" aria-hidden="true" style="font-size: 3rem; opacity: 0.5; margin-bottom: 1rem;"></i>
<p>Original file not available</p>
</div>
{% endif %}
@@ -1227,7 +1227,7 @@
</div>
<div class="pdf-canvas-wrapper" id="processed-canvas-wrapper">
<div class="pdf-loading">
<i class="fas fa-spinner fa-spin" style="font-size: 2rem; margin-bottom: 1rem;"></i>
<i class="fas fa-spinner fa-spin" aria-hidden="true" style="font-size: 2rem; margin-bottom: 1rem;"></i>
<p>Loading PDF...</p>
</div>
</div>
@@ -1236,11 +1236,11 @@
onclick="loadAndShowText('processed', {{ file.id }})"
style="margin-top: 0.5rem; background-color: #48bb78; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600; width: 100%;"
>
<i class="fas fa-file-alt"></i> View Extracted Text
<i class="fas fa-file-alt" aria-hidden="true"></i> View Extracted Text
</button>
{% else %}
<div style="text-align: center; padding: 3rem; background-color: #f7fafc; border-radius: 0.5rem; color: #718096;">
<i class="fas fa-file-pdf" style="font-size: 3rem; opacity: 0.5; margin-bottom: 1rem;"></i>
<i class="fas fa-file-pdf" aria-hidden="true" style="font-size: 3rem; opacity: 0.5; margin-bottom: 1rem;"></i>
<p>Processed file not available yet</p>
</div>
{% endif %}
@@ -1259,14 +1259,16 @@
id="original-copy-btn"
onclick="copyTextToClipboard('original')"
style="background-color: #4299e1; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600;"
aria-label="Copy extracted text"
>
<i class="fas fa-copy"></i> Copy
<i class="fas fa-copy" aria-hidden="true"></i> Copy
</button>
<button
onclick="toggleTextModal('original-text-modal')"
style="background-color: #f56565; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600;"
aria-label="Close modal"
>
<i class="fas fa-times"></i> Close
<i class="fas fa-times" aria-hidden="true"></i> Close
</button>
</div>
</div>
@@ -1288,14 +1290,16 @@
id="processed-copy-btn"
onclick="copyTextToClipboard('processed')"
style="background-color: #4299e1; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600;"
aria-label="Copy extracted text"
>
<i class="fas fa-copy"></i> Copy
<i class="fas fa-copy" aria-hidden="true"></i> Copy
</button>
<button
onclick="toggleTextModal('processed-text-modal')"
style="background-color: #f56565; color: white; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; cursor: pointer; font-weight: 600;"
aria-label="Close modal"
>
<i class="fas fa-times"></i> Close
<i class="fas fa-times" aria-hidden="true"></i> Close
</button>
</div>
</div>
+26 -23
View File
@@ -100,8 +100,8 @@
{% elif file %}
<!-- ── Back + header ── -->
<a href="/files" style="display:inline-flex;align-items:center;gap:0.4rem;color:#3b82f6;font-weight:600;text-decoration:none;margin-bottom:1.25rem;">
<i class="fas fa-arrow-left"></i> Back to Files
<a href="/files" style="display:inline-flex;align-items:center;gap:0.4rem;color:#3b82f6;font-weight:600;text-decoration:none;margin-bottom:1.25rem;" aria-label="Back to Files">
<i class="fas fa-arrow-left" aria-hidden="true"></i> Back to Files
</a>
<div class="doc-header">
@@ -121,23 +121,23 @@
<div style="display:flex;align-items:center;gap:0.75rem;flex-wrap:wrap;">
<!-- Status pill -->
{% if file.is_duplicate %}
<span class="status-pill pill-duplicate"><i class="fas fa-copy"></i> Duplicate</span>
<span class="status-pill pill-duplicate"><i class="fas fa-copy" aria-hidden="true"></i> Duplicate</span>
{% elif step_summary %}
{% set main_completed = step_summary.main.success + step_summary.main.skipped %}
{% if step_summary.main.failure > 0 or step_summary.uploads.failure > 0 %}
<span class="status-pill pill-failed"><i class="fas fa-times-circle"></i> Failed</span>
<span class="status-pill pill-failed"><i class="fas fa-times-circle" aria-hidden="true"></i> Failed</span>
{% elif step_summary.main["in_progress"] > 0 or step_summary.uploads["in_progress"] > 0 %}
<span class="status-pill pill-processing"><i class="fas fa-circle-notch fa-spin"></i> Processing</span>
<span class="status-pill pill-processing"><i class="fas fa-circle-notch fa-spin" aria-hidden="true"></i> Processing</span>
{% elif step_summary.total_main_steps > 0 and main_completed == step_summary.total_main_steps and step_summary.main.failure == 0 %}
<span class="status-pill pill-completed"><i class="fas fa-check-circle"></i> Completed</span>
<span class="status-pill pill-completed"><i class="fas fa-check-circle" aria-hidden="true"></i> Completed</span>
{% else %}
<span class="status-pill pill-pending"><i class="fas fa-pause-circle"></i> Pending</span>
<span class="status-pill pill-pending"><i class="fas fa-pause-circle" aria-hidden="true"></i> Pending</span>
{% endif %}
{% endif %}
<!-- Process detail link -->
<a href="/files/{{ file.id }}/detail" class="action-btn btn-process">
<i class="fas fa-cogs"></i> Processing Details
<i class="fas fa-cogs" aria-hidden="true"></i> Processing Details
</a>
</div>
</div>
@@ -149,7 +149,7 @@
<div>
{% if gpt_metadata %}
<div class="doc-card">
<div class="doc-card-title"><i class="fas fa-tags" style="color:#3b82f6;margin-right:0.4rem;"></i>Document Metadata</div>
<div class="doc-card-title"><i class="fas fa-tags" aria-hidden="true" style="color:#3b82f6;margin-right:0.4rem;"></i>Document Metadata</div>
{% if gpt_metadata.document_type %}
<div class="meta-row">
@@ -221,7 +221,7 @@
<!-- File info -->
<div class="doc-card">
<div class="doc-card-title"><i class="fas fa-info-circle" style="color:#6b7280;margin-right:0.4rem;"></i>File Info</div>
<div class="doc-card-title"><i class="fas fa-info-circle" aria-hidden="true" style="color:#6b7280;margin-right:0.4rem;"></i>File Info</div>
<div class="info-row">
<span class="info-key">Uploaded</span>
<span class="info-val">{{ file.created_at.strftime('%Y-%m-%d %H:%M') if file.created_at else 'N/A' }}</span>
@@ -246,25 +246,25 @@
<!-- Actions -->
<div class="doc-card">
<div class="doc-card-title"><i class="fas fa-bolt" style="color:#f59e0b;margin-right:0.4rem;"></i>Actions</div>
<div class="doc-card-title"><i class="fas fa-bolt" aria-hidden="true" style="color:#f59e0b;margin-right:0.4rem;"></i>Actions</div>
<div style="display:flex;flex-wrap:wrap;gap:0.6rem;">
{% if processed_file_exists %}
<a href="/api/files/{{ file.id }}/download?version=processed" class="action-btn btn-primary">
<i class="fas fa-download"></i> Download (processed)
<i class="fas fa-download" aria-hidden="true"></i> Download (processed)
</a>
{% endif %}
{% if original_file_exists %}
<a href="/api/files/{{ file.id }}/download?version=original" class="action-btn btn-secondary">
<i class="fas fa-download"></i> Download (original)
<i class="fas fa-download" aria-hidden="true"></i> Download (original)
</a>
{% endif %}
{% if processed_file_exists %}
<a href="/api/files/{{ file.id }}/preview?version=processed" target="_blank" class="action-btn btn-secondary">
<i class="fas fa-external-link-alt"></i> Open processed
<i class="fas fa-external-link-alt" aria-hidden="true"></i> Open processed
</a>
{% elif original_file_exists %}
<a href="/api/files/{{ file.id }}/preview?version=original" target="_blank" class="action-btn btn-secondary">
<i class="fas fa-external-link-alt"></i> Open original
<i class="fas fa-external-link-alt" aria-hidden="true"></i> Open original
</a>
{% endif %}
</div>
@@ -274,7 +274,7 @@
<!-- RIGHT: PDF preview -->
<div>
<div class="doc-card" style="padding:1rem;">
<div class="doc-card-title"><i class="fas fa-file-pdf" style="color:#ef4444;margin-right:0.4rem;"></i>Preview</div>
<div class="doc-card-title"><i class="fas fa-file-pdf" aria-hidden="true" style="color:#ef4444;margin-right:0.4rem;"></i>Preview</div>
{% if processed_file_exists %}
<iframe
src="/api/files/{{ file.id }}/preview?version=processed"
@@ -303,14 +303,14 @@
{% if file.ocr_text %}
<div class="doc-card">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.75rem;">
<div class="doc-card-title" style="margin:0;"><i class="fas fa-align-left" style="color:#8b5cf6;margin-right:0.4rem;"></i>Extracted Text</div>
<div class="doc-card-title" style="margin:0;"><i class="fas fa-align-left" aria-hidden="true" style="color:#8b5cf6;margin-right:0.4rem;"></i>Extracted Text</div>
<div style="display:flex;gap:0.5rem;">
<button class="text-toggle" onclick="toggleOcrText()">
<i id="ocr-toggle-icon" class="fas fa-chevron-down"></i>
<button class="text-toggle" onclick="toggleOcrText()" aria-expanded="false" aria-controls="ocr-text-block">
<i id="ocr-toggle-icon" class="fas fa-chevron-down" aria-hidden="true"></i>
<span id="ocr-toggle-label">Show text</span>
</button>
<button class="text-toggle" onclick="copyOcrText()" id="ocr-copy-btn" style="color:#10b981;">
<i class="fas fa-copy"></i> Copy
<button class="text-toggle" onclick="copyOcrText()" id="ocr-copy-btn" style="color:#10b981;" aria-label="Copy extracted text">
<i class="fas fa-copy" aria-hidden="true"></i> Copy
</button>
</div>
</div>
@@ -321,9 +321,9 @@
{% elif processed_file_exists or original_file_exists %}
<div class="doc-card">
<div style="display:flex;justify-content:space-between;align-items:center;">
<div class="doc-card-title" style="margin:0;"><i class="fas fa-align-left" style="color:#8b5cf6;margin-right:0.4rem;"></i>Extracted Text</div>
<div class="doc-card-title" style="margin:0;"><i class="fas fa-align-left" aria-hidden="true" style="color:#8b5cf6;margin-right:0.4rem;"></i>Extracted Text</div>
<button class="action-btn btn-secondary" onclick="loadText({{ file.id }})">
<i class="fas fa-file-alt"></i> Extract &amp; show text
<i class="fas fa-file-alt" aria-hidden="true"></i> Extract &amp; show text
</button>
</div>
<div id="text-load-area" style="margin-top:0.75rem;"></div>
@@ -343,14 +343,17 @@
var block = document.getElementById('ocr-text-block');
var icon = document.getElementById('ocr-toggle-icon');
var label = document.getElementById('ocr-toggle-label');
var btn = icon.closest('button');
if (block.style.display === 'none') {
block.style.display = 'block';
icon.className = 'fas fa-chevron-up';
label.textContent = 'Hide text';
if (btn) btn.setAttribute('aria-expanded', 'true');
} else {
block.style.display = 'none';
icon.className = 'fas fa-chevron-down';
label.textContent = 'Show text';
if (btn) btn.setAttribute('aria-expanded', 'false');
}
}
+17 -17
View File
@@ -13,10 +13,10 @@
</div>
<div class="flex flex-wrap gap-3">
<a href="/upload" class="bg-white text-blue-700 hover:bg-blue-50 font-semibold py-2 px-5 rounded-lg transition duration-200 flex items-center shadow-sm">
<i class="fas fa-upload mr-2"></i> Upload
<i class="fas fa-upload mr-2" aria-hidden="true"></i> Upload
</a>
<a href="/files" class="bg-transparent border border-white text-white hover:bg-white hover:text-blue-700 font-semibold py-2 px-5 rounded-lg transition duration-200 flex items-center">
<i class="fas fa-list mr-2"></i> Browse Files
<i class="fas fa-list mr-2" aria-hidden="true"></i> Browse Files
</a>
</div>
</div>
@@ -26,7 +26,7 @@
<div class="grid grid-cols-1 sm:grid-cols-3 gap-6 mb-8">
<div class="bg-white rounded-xl shadow p-6 flex items-center gap-4">
<div class="h-12 w-12 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
<i class="fas fa-file-alt text-blue-600 text-xl"></i>
<i class="fas fa-file-alt text-blue-600 text-xl" aria-hidden="true"></i>
</div>
<div>
<p class="text-3xl font-bold text-blue-600">{{ stats.processed_files | default(0) }}</p>
@@ -35,7 +35,7 @@
</div>
<div class="bg-white rounded-xl shadow p-6 flex items-center gap-4">
<div class="h-12 w-12 rounded-full bg-green-100 flex items-center justify-center flex-shrink-0">
<i class="fas fa-plug text-green-600 text-xl"></i>
<i class="fas fa-plug text-green-600 text-xl" aria-hidden="true"></i>
</div>
<div>
<p class="text-3xl font-bold text-green-600">{{ stats.active_integrations | default(0) }}</p>
@@ -44,7 +44,7 @@
</div>
<div class="bg-white rounded-xl shadow p-6 flex items-center gap-4">
<div class="h-12 w-12 rounded-full bg-indigo-100 flex items-center justify-center flex-shrink-0">
<i class="fas fa-database text-indigo-600 text-xl"></i>
<i class="fas fa-database text-indigo-600 text-xl" aria-hidden="true"></i>
</div>
<div>
<p class="text-3xl font-bold text-indigo-600">{{ stats.storage_targets | default(0) }}</p>
@@ -59,13 +59,13 @@
<!-- Quick Actions Widget -->
<div class="bg-white rounded-xl shadow p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<i class="fas fa-bolt text-yellow-500"></i> Quick Actions
<i class="fas fa-bolt text-yellow-500" aria-hidden="true"></i> Quick Actions
</h2>
<ul class="space-y-2">
<li>
<a href="/upload" class="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition group">
<span class="h-8 w-8 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0 group-hover:bg-blue-200">
<i class="fas fa-upload text-blue-600 text-sm"></i>
<i class="fas fa-upload text-blue-600 text-sm" aria-hidden="true"></i>
</span>
<div>
<p class="text-sm font-medium text-gray-800">Upload Document</p>
@@ -76,7 +76,7 @@
<li>
<a href="/files" class="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition group">
<span class="h-8 w-8 rounded-full bg-indigo-100 flex items-center justify-center flex-shrink-0 group-hover:bg-indigo-200">
<i class="fas fa-list text-indigo-600 text-sm"></i>
<i class="fas fa-list text-indigo-600 text-sm" aria-hidden="true"></i>
</span>
<div>
<p class="text-sm font-medium text-gray-800">View All Files</p>
@@ -87,7 +87,7 @@
<li>
<a href="/status" class="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-50 transition group">
<span class="h-8 w-8 rounded-full bg-green-100 flex items-center justify-center flex-shrink-0 group-hover:bg-green-200">
<i class="fas fa-heartbeat text-green-600 text-sm"></i>
<i class="fas fa-heartbeat text-green-600 text-sm" aria-hidden="true"></i>
</span>
<div>
<p class="text-sm font-medium text-gray-800">System Status</p>
@@ -101,27 +101,27 @@
<!-- Capabilities Widget -->
<div class="bg-white rounded-xl shadow p-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<i class="fas fa-cubes text-blue-500"></i> Capabilities
<i class="fas fa-cubes text-blue-500" aria-hidden="true"></i> Capabilities
</h2>
<ul class="space-y-3 text-sm text-gray-600">
<li class="flex items-start gap-2">
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0"></i>
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0" aria-hidden="true"></i>
<span>OCR &amp; metadata extraction with AI</span>
</li>
<li class="flex items-start gap-2">
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0"></i>
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0" aria-hidden="true"></i>
<span>Cloud storage: Dropbox, OneDrive, Google Drive, NextCloud</span>
</li>
<li class="flex items-start gap-2">
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0"></i>
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0" aria-hidden="true"></i>
<span>Paperless-ngx integration for document management</span>
</li>
<li class="flex items-start gap-2">
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0"></i>
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0" aria-hidden="true"></i>
<span>Email &amp; URL-based document ingestion</span>
</li>
<li class="flex items-start gap-2">
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0"></i>
<i class="fas fa-check-circle text-green-500 mt-0.5 flex-shrink-0" aria-hidden="true"></i>
<span>Automated classification &amp; routing workflows</span>
</li>
</ul>
@@ -131,7 +131,7 @@
<div class="bg-white rounded-xl shadow p-6 flex flex-col justify-between">
<div>
<h2 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2">
<i class="fas fa-compass text-indigo-500"></i> Getting Started
<i class="fas fa-compass text-indigo-500" aria-hidden="true"></i> Getting Started
</h2>
<ol class="space-y-3 text-sm text-gray-600 list-none">
<li class="flex items-start gap-2">
@@ -149,7 +149,7 @@
</ol>
</div>
<a href="/about" class="mt-6 inline-flex items-center text-sm text-indigo-600 hover:text-indigo-800 font-medium">
Learn more about DocuElevate <i class="fas fa-arrow-right ml-1 text-xs"></i>
Learn more about DocuElevate <i class="fas fa-arrow-right ml-1 text-xs" aria-hidden="true"></i>
</a>
</div>
</div>
+12 -12
View File
@@ -11,14 +11,14 @@
<!-- Header -->
<div class="mb-6">
<h1 class="text-3xl font-bold mb-2">
<i class="fas fa-stream mr-2 text-blue-500"></i>Queue Monitor
<i class="fas fa-stream mr-2 text-blue-500" aria-hidden="true"></i>Queue Monitor
</h1>
<p class="text-gray-600">Real-time view of the document processing pipeline and Celery task queues.</p>
</div>
<!-- Loading state -->
<div id="queueLoading" class="text-center py-12">
<i class="fas fa-spinner fa-spin fa-2x text-blue-400"></i>
<i class="fas fa-spinner fa-spin fa-2x text-blue-400" aria-hidden="true"></i>
<p class="mt-2 text-gray-500">Loading queue statistics&hellip;</p>
</div>
@@ -31,12 +31,12 @@
<div id="queueContent" class="hidden">
<!-- Summary Cards -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-8" aria-live="polite">
<!-- Queued -->
<div class="bg-white rounded-lg shadow p-5">
<div class="flex items-center">
<div class="flex-shrink-0 bg-yellow-100 rounded-full p-3">
<i class="fas fa-inbox text-yellow-600 text-xl"></i>
<i class="fas fa-inbox text-yellow-600 text-xl" aria-hidden="true"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Queued Tasks</p>
@@ -48,7 +48,7 @@
<div class="bg-white rounded-lg shadow p-5">
<div class="flex items-center">
<div class="flex-shrink-0 bg-blue-100 rounded-full p-3">
<i class="fas fa-cogs text-blue-600 text-xl"></i>
<i class="fas fa-cogs text-blue-600 text-xl" aria-hidden="true"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Active Tasks</p>
@@ -60,7 +60,7 @@
<div class="bg-white rounded-lg shadow p-5">
<div class="flex items-center">
<div class="flex-shrink-0 bg-indigo-100 rounded-full p-3">
<i class="fas fa-file-alt text-indigo-600 text-xl"></i>
<i class="fas fa-file-alt text-indigo-600 text-xl" aria-hidden="true"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Files Processing</p>
@@ -72,7 +72,7 @@
<div class="bg-white rounded-lg shadow p-5">
<div class="flex items-center">
<div class="flex-shrink-0 bg-green-100 rounded-full p-3">
<i class="fas fa-server text-green-600 text-xl"></i>
<i class="fas fa-server text-green-600 text-xl" aria-hidden="true"></i>
</div>
<div class="ml-4">
<p class="text-sm font-medium text-gray-500">Workers Online</p>
@@ -89,7 +89,7 @@
<div class="bg-white rounded-lg shadow">
<div class="px-5 py-4 border-b border-gray-200">
<h2 class="text-lg font-semibold text-gray-900">
<i class="fas fa-list-ol mr-2 text-gray-500"></i>Redis Queues
<i class="fas fa-list-ol mr-2 text-gray-500" aria-hidden="true"></i>Redis Queues
</h2>
</div>
<div class="p-5">
@@ -111,7 +111,7 @@
<div class="bg-white rounded-lg shadow">
<div class="px-5 py-4 border-b border-gray-200">
<h2 class="text-lg font-semibold text-gray-900">
<i class="fas fa-database mr-2 text-gray-500"></i>Processing Pipeline
<i class="fas fa-database mr-2 text-gray-500" aria-hidden="true"></i>Processing Pipeline
</h2>
</div>
<div class="p-5">
@@ -134,7 +134,7 @@
<div class="bg-white rounded-lg shadow mb-8">
<div class="px-5 py-4 border-b border-gray-200">
<h2 class="text-lg font-semibold text-gray-900">
<i class="fas fa-play-circle mr-2 text-blue-500"></i>Active Tasks
<i class="fas fa-play-circle mr-2 text-blue-500" aria-hidden="true"></i>Active Tasks
<span id="activeCount" class="ml-1 text-sm font-normal text-gray-500">(0)</span>
</h2>
</div>
@@ -158,7 +158,7 @@
<div class="bg-white rounded-lg shadow mb-8">
<div class="px-5 py-4 border-b border-gray-200">
<h2 class="text-lg font-semibold text-gray-900">
<i class="fas fa-file-medical-alt mr-2 text-indigo-500"></i>Recently Processing Files
<i class="fas fa-file-medical-alt mr-2 text-indigo-500" aria-hidden="true"></i>Recently Processing Files
</h2>
</div>
<div class="p-5 overflow-x-auto">
@@ -179,7 +179,7 @@
<!-- Auto-refresh info -->
<div class="text-center text-gray-400 text-xs mb-4">
<i class="fas fa-sync-alt mr-1"></i>
<i class="fas fa-sync-alt mr-1" aria-hidden="true"></i>
Auto-refreshes every <span id="refreshInterval">10</span> seconds &mdash;
Last updated: <span id="lastUpdated"></span>
</div>
+10 -9
View File
@@ -23,31 +23,31 @@
<div class="flex items-center gap-2">
<a href="/setup?step=1"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
<i class="fas fa-magic mr-2"></i> Setup Wizard
<i class="fas fa-magic mr-2" aria-hidden="true"></i> Setup Wizard
</a>
<div class="relative" x-data="{ exportOpen: false }">
<button @click="exportOpen = !exportOpen"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
<i class="fas fa-download mr-2"></i> Export .env
<i class="fas fa-chevron-down ml-1 text-xs"></i>
<i class="fas fa-download mr-2" aria-hidden="true"></i> Export .env
<i class="fas fa-chevron-down ml-1 text-xs" aria-hidden="true"></i>
</button>
<div x-show="exportOpen" @click.outside="exportOpen = false" x-transition
class="absolute right-0 mt-1 w-52 bg-white border border-gray-200 rounded-md shadow-lg z-10">
<a href="/api/settings/export-env?source=db"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
@click="exportOpen = false">
<i class="fas fa-database mr-2 text-green-600"></i>DB settings only
<i class="fas fa-database mr-2 text-green-600" aria-hidden="true"></i>DB settings only
</a>
<a href="/api/settings/export-env?source=effective"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50"
@click="exportOpen = false">
<i class="fas fa-layer-group mr-2 text-blue-600"></i>Full effective config
<i class="fas fa-layer-group mr-2 text-blue-600" aria-hidden="true"></i>Full effective config
</a>
</div>
</div>
<a href="/admin/settings/audit-log"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
<i class="fas fa-history mr-2"></i> Audit Log
<i class="fas fa-history mr-2" aria-hidden="true"></i> Audit Log
</a>
</div>
</div>
@@ -179,7 +179,7 @@
{% endfor %}
</datalist>
<p class="text-xs text-gray-400 mt-1">
<i class="fas fa-info-circle mr-1"></i>
<i class="fas fa-info-circle mr-1" aria-hidden="true"></i>
Pick from the list or type any model name supported by your provider.
</p>
</div>
@@ -222,6 +222,7 @@
@click="togglePassword('{{ setting.key }}')"
class="text-gray-400 hover:text-gray-600 focus:outline-none"
title="Show/hide value"
aria-label="Toggle password visibility"
>
<i :class="showPassword['{{ setting.key }}'] ? 'fas fa-eye-slash' : 'fas fa-eye'"></i>
</button>
@@ -253,7 +254,7 @@
class="px-3 py-1 text-sm bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap"
title="Remove DB override and revert to environment variable or default"
>
<span x-show="revertingKey !== '{{ setting.key }}'"><i class="fas fa-trash-alt mr-1"></i>Remove from DB</span>
<span x-show="revertingKey !== '{{ setting.key }}'"><i class="fas fa-trash-alt mr-1" aria-hidden="true"></i>Remove from DB</span>
<span x-show="revertingKey === '{{ setting.key }}'">Reverting…</span>
</button>
<button
@@ -265,7 +266,7 @@
class="px-3 py-1 text-sm bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap"
title="Save this setting"
>
<span x-show="savingKey !== '{{ setting.key }}'"><i class="fas fa-save mr-1"></i>Save</span>
<span x-show="savingKey !== '{{ setting.key }}'"><i class="fas fa-save mr-1" aria-hidden="true"></i>Save</span>
<span x-show="savingKey === '{{ setting.key }}'">Saving…</span>
</button>
</div>
+6 -6
View File
@@ -31,14 +31,14 @@
</div>
</div>
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3" aria-live="polite">
{% for name, provider in providers.items() %}
<div class="bg-white overflow-hidden shadow rounded-lg">
<div class="px-4 py-5 sm:px-6 flex justify-between items-center">
<div class="flex items-center">
<span class="inline-flex items-center justify-center h-10 w-10 rounded-md {{ 'bg-green-500' if provider.configured else 'bg-gray-400' }} text-white mr-3">
<!-- Use Font Awesome icon -->
<i class="{{ provider.icon }} fa-lg"></i>
<i class="{{ provider.icon }} fa-lg" aria-hidden="true"></i>
</span>
<h3 class="text-lg leading-6 font-medium text-gray-900">{{ name }}</h3>
</div>
@@ -232,7 +232,7 @@
</div>
<!-- Result Modal -->
<div id="resultModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog">
<div id="resultModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog" aria-labelledby="modalTitle">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-1/2 lg:w-1/3 shadow-lg rounded-md bg-white">
<div class="mt-3 text-center">
<div id="modalIcon" class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100 mb-4">
@@ -254,7 +254,7 @@
</div>
<!-- Details Modal -->
<div id="detailsModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog">
<div id="detailsModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog" aria-labelledby="detailsModalTitle">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-2/3 lg:w-1/2 shadow-lg rounded-md bg-white">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button type="button" id="closeDetailsModal" class="text-gray-400 hover:text-gray-500">
@@ -281,7 +281,7 @@
</div>
<!-- AI Extraction Test Modal -->
<div id="aiExtractionModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog">
<div id="aiExtractionModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden overflow-y-auto h-full w-full z-50" aria-modal="true" role="dialog" aria-labelledby="aiExtractionModalTitle">
<div class="relative top-10 mx-auto p-5 border w-11/12 md:w-3/4 lg:w-2/3 xl:w-1/2 shadow-lg rounded-md bg-white">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button type="button" id="closeAiExtractionModal" class="text-gray-400 hover:text-gray-500">
@@ -290,7 +290,7 @@
</button>
</div>
<div class="mt-3">
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-1">
<h3 id="aiExtractionModalTitle" class="text-lg leading-6 font-medium text-gray-900 mb-1">
<i class="fa-solid fa-flask mr-2 text-indigo-600"></i>AI Extraction Test
</h3>
<p class="text-sm text-gray-500 mb-4">