f852ba9783
- /files/<id> → new summary page with navigation cards - /files/<id>/detail → document detail with metadata, preview, text - /files/<id>/process → processing pipeline status and history - /files/<id>/annotations → comments & annotations with EmbedPDF viewer - /files/<id>/comments → redirects to /annotations - Added embed-pdf-viewer as git submodule for PDF annotation viewer - Updated all navigation links across templates - Updated all tests to use new URL structure Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/12276514-bd3d-4e3e-84d9-5977d1f82b19
197 lines
9.5 KiB
HTML
197 lines
9.5 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ file.document_title or file.original_filename or 'Document' }} - DocuElevate{% endblock %}
|
|
|
|
{% block head_extra %}
|
|
<script src="/static/js/common.js"></script>
|
|
<style>
|
|
.summary-container { max-width: 900px; margin: 0 auto; }
|
|
|
|
/* ── header ── */
|
|
.summary-header {
|
|
display: flex; align-items: flex-start; justify-content: space-between;
|
|
gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap;
|
|
}
|
|
.summary-title { font-size: 1.75rem; font-weight: 700; color: #1f2937; line-height: 1.25; }
|
|
.summary-subtitle { font-size: 0.9rem; color: #6b7280; margin-top: 0.25rem; font-family: monospace; }
|
|
.dark .summary-title { color: #f3f4f6; }
|
|
.dark .summary-subtitle { color: #9ca3af; }
|
|
|
|
/* ── status pill ── */
|
|
.status-pill {
|
|
display: inline-flex; align-items: center; gap: 0.4rem;
|
|
padding: 0.35rem 0.85rem; border-radius: 9999px;
|
|
font-size: 0.8rem; font-weight: 600; white-space: nowrap;
|
|
}
|
|
.pill-completed { background: #d1fae5; color: #065f46; }
|
|
.pill-failed { background: #fee2e2; color: #991b1b; }
|
|
.pill-processing { background: #dbeafe; color: #1e3a8a; }
|
|
.pill-pending { background: #fef3c7; color: #92400e; }
|
|
.pill-duplicate { background: #e5e7eb; color: #374151; }
|
|
|
|
/* ── cards ── */
|
|
.summary-card {
|
|
background: white; border-radius: 0.5rem;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,.08);
|
|
padding: 1.5rem; margin-bottom: 1.25rem;
|
|
}
|
|
.dark .summary-card { background: #1f2937; box-shadow: 0 1px 3px rgba(0,0,0,.3); }
|
|
.summary-card-title {
|
|
font-size: 1rem; font-weight: 700; color: #374151;
|
|
text-transform: uppercase; letter-spacing: 0.05em;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.dark .summary-card-title { color: #d1d5db; }
|
|
|
|
/* ── info rows ── */
|
|
.info-row { display: flex; justify-content: space-between; padding: 0.4rem 0; border-bottom: 1px solid #f3f4f6; font-size: 0.875rem; }
|
|
.info-row:last-child { border-bottom: none; }
|
|
.info-key { color: #6b7280; }
|
|
.info-val { color: #1f2937; font-family: monospace; text-align: right; word-break: break-all; max-width: 60%; }
|
|
.dark .info-row { border-bottom-color: #374151; }
|
|
.dark .info-key { color: #9ca3af; }
|
|
.dark .info-val { color: #e5e7eb; }
|
|
|
|
/* ── nav cards ── */
|
|
.nav-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.25rem; }
|
|
@media (max-width: 768px) { .nav-grid { grid-template-columns: 1fr; } }
|
|
.nav-card {
|
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
background: white; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0,0,0,.08);
|
|
padding: 1.5rem; text-decoration: none; color: #374151;
|
|
transition: box-shadow 0.15s, transform 0.15s; min-height: 120px;
|
|
}
|
|
.nav-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,.15); transform: translateY(-2px); }
|
|
.dark .nav-card { background: #1f2937; color: #e5e7eb; }
|
|
.dark .nav-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,.4); }
|
|
.nav-card i { font-size: 1.5rem; margin-bottom: 0.75rem; }
|
|
.nav-card-title { font-weight: 700; font-size: 0.95rem; margin-bottom: 0.25rem; }
|
|
.nav-card-desc { font-size: 0.8rem; color: #6b7280; text-align: center; }
|
|
.dark .nav-card-desc { color: #9ca3af; }
|
|
|
|
/* ── action buttons ── */
|
|
.action-btn {
|
|
display: inline-flex; align-items: center; gap: 0.4rem;
|
|
padding: 0.5rem 1.1rem; border-radius: 0.375rem;
|
|
font-size: 0.875rem; font-weight: 600; text-decoration: none;
|
|
cursor: pointer; border: none; transition: filter 0.1s;
|
|
}
|
|
.action-btn:hover { filter: brightness(0.92); }
|
|
.btn-primary { background: #3b82f6; color: white; }
|
|
.btn-secondary { background: #f3f4f6; color: #374151; }
|
|
|
|
/* ── error ── */
|
|
.error-box { background: #fee2e2; border: 1px solid #f87171; color: #b91c1c; padding: 1rem; border-radius: 0.375rem; margin-bottom: 1rem; }
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="summary-container">
|
|
|
|
{% if error %}
|
|
<div class="error-box"><strong>Error:</strong> {{ error }}</div>
|
|
{% 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;" aria-label="Back to Files">
|
|
<i class="fas fa-arrow-left" aria-hidden="true"></i> Back to Files
|
|
</a>
|
|
|
|
<div class="summary-header">
|
|
<div>
|
|
<div class="summary-title">
|
|
{% if gpt_metadata and gpt_metadata.filename %}
|
|
{{ gpt_metadata.filename | replace('.pdf','') | replace('_',' ') }}
|
|
{% elif file.document_title %}
|
|
{{ file.document_title }}
|
|
{% else %}
|
|
{{ file.original_filename or '(untitled)' }}
|
|
{% endif %}
|
|
</div>
|
|
<div class="summary-subtitle">{{ file.original_filename }}</div>
|
|
</div>
|
|
|
|
<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" 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" 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" 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" aria-hidden="true"></i> Completed</span>
|
|
{% else %}
|
|
<span class="status-pill pill-pending"><i class="fas fa-pause-circle" aria-hidden="true"></i> Pending</span>
|
|
{% endif %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── Navigation cards ── -->
|
|
<nav class="nav-grid" aria-label="File sections">
|
|
<a href="/files/{{ file.id }}/detail" class="nav-card">
|
|
<i class="fas fa-file-alt" aria-hidden="true" style="color:#3b82f6;"></i>
|
|
<div class="nav-card-title">Document Detail</div>
|
|
<div class="nav-card-desc">Metadata, preview & extracted text</div>
|
|
</a>
|
|
<a href="/files/{{ file.id }}/process" class="nav-card">
|
|
<i class="fas fa-cogs" aria-hidden="true" style="color:#6366f1;"></i>
|
|
<div class="nav-card-title">Processing</div>
|
|
<div class="nav-card-desc">Pipeline status & processing history</div>
|
|
</a>
|
|
<a href="/files/{{ file.id }}/annotations" class="nav-card">
|
|
<i class="fas fa-comments" aria-hidden="true" style="color:#10b981;"></i>
|
|
<div class="nav-card-title">Comments & Annotations</div>
|
|
<div class="nav-card-desc">Discussion & document annotations</div>
|
|
</a>
|
|
</nav>
|
|
|
|
<!-- ── File info card ── -->
|
|
<div class="summary-card">
|
|
<div class="summary-card-title"><i class="fas fa-info-circle" aria-hidden="true" style="color:#6366f1;margin-right:0.4rem;"></i>File Information</div>
|
|
<div class="info-row"><span class="info-key">File ID</span><span class="info-val">{{ file.id }}</span></div>
|
|
<div class="info-row"><span class="info-key">Filename</span><span class="info-val">{{ file.original_filename }}</span></div>
|
|
<div class="info-row"><span class="info-key">Size</span><span class="info-val">{{ (file.file_size / 1024) | round(1) }} KB</span></div>
|
|
<div class="info-row"><span class="info-key">MIME Type</span><span class="info-val">{{ file.mime_type or 'unknown' }}</span></div>
|
|
<div class="info-row"><span class="info-key">Created</span><span class="info-val">{{ file.created_at.strftime('%Y-%m-%d %H:%M') if file.created_at else 'N/A' }}</span></div>
|
|
{% if file.detected_language %}
|
|
<div class="info-row"><span class="info-key">Language</span><span class="info-val">{{ file.detected_language }}</span></div>
|
|
{% endif %}
|
|
{% if pipeline_info %}
|
|
<div class="info-row"><span class="info-key">Pipeline</span><span class="info-val">{{ pipeline_info.name }}</span></div>
|
|
{% endif %}
|
|
{% if file.document_title %}
|
|
<div class="info-row"><span class="info-key">Document Title</span><span class="info-val">{{ file.document_title }}</span></div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- ── Quick actions ── -->
|
|
<div class="summary-card">
|
|
<div class="summary-card-title"><i class="fas fa-bolt" aria-hidden="true" style="color:#f59e0b;margin-right:0.4rem;"></i>Quick Actions</div>
|
|
<div style="display:flex;gap:0.75rem;flex-wrap:wrap;">
|
|
{% if processed_file_exists %}
|
|
<a href="/api/files/{{ file.id }}/download?version=processed" class="action-btn btn-primary">
|
|
<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" aria-hidden="true"></i> Download Original
|
|
</a>
|
|
{% endif %}
|
|
<a href="/files/{{ file.id }}/detail" class="action-btn btn-secondary">
|
|
<i class="fas fa-eye" aria-hidden="true"></i> View Detail
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% else %}
|
|
<!-- file is None without error -->
|
|
<div class="error-box">Document not found.</div>
|
|
{% endif %}
|
|
|
|
</div>
|
|
{% endblock %}
|