UI style refresh continued

This commit is contained in:
Jim Lancaster
2026-08-03 15:15:58 -05:00
parent 4f6e1fd913
commit 752346025b
30 changed files with 328 additions and 651 deletions
+9 -5
View File
@@ -15,7 +15,6 @@ from transcription.config import Settings
from transcription.config import get_settings
from transcription.db.engine import get_database_url
from transcription.db.engine import get_engine
from transcription.db.operations import create_all
from transcription.db.session import dispose_session_factory
from transcription.db.session import get_session_factory
from transcription.db.session import session_scope
@@ -42,8 +41,15 @@ async def default_settings():
"""Provide default settings for tests."""
settings = get_settings(database_url="sqlite:///:memory:")
db_url = get_database_url(settings)
await create_all(engine=get_engine(database_url=db_url))
return settings
engine = get_engine(database_url=db_url)
# Cached in-memory engines persist across tests; reset schema per test for isolation.
async with engine.begin() as connection:
await connection.run_sync(SQLModel.metadata.drop_all)
await connection.run_sync(SQLModel.metadata.create_all)
yield settings
await dispose_session_factory(db_url)
@pytest_asyncio.fixture
@@ -53,8 +59,6 @@ async def async_session(default_settings: Settings):
async with session_scope(database_url=db_url) as async_session:
yield async_session
await dispose_session_factory(db_url)
@pytest.fixture
def default_session_factory(default_settings: Settings):
+12 -3
View File
@@ -8,8 +8,9 @@ from transcription.config import Settings
from transcription.db.models import Job
from transcription.db.models import JobStatus
from transcription.providers.base import TranscriptionResult
from transcription.services import ServiceBundle
from transcription.services.store import create_upload_job
from transcription.worker import process_next_queued_job
from transcription.services.workflows import advance_job
@pytest.mark.integration
@@ -58,7 +59,11 @@ class TestPipelineSuccessFlow:
_fake_transcribe_document_image,
)
processed = await process_next_queued_job(session=async_session)
services = ServiceBundle()
queued_job = await services.jobs.read_next_queued_job(session=async_session)
processed = queued_job is not None
if queued_job is not None:
await advance_job(job=queued_job, services=services, session=async_session)
job = await async_session.get(Job, upload_result.job_id)
assert processed is True
@@ -98,7 +103,11 @@ class TestPipelineFailureFlow:
_fake_transcribe_document_image,
)
processed = await process_next_queued_job(session=async_session)
services = ServiceBundle()
queued_job = await services.jobs.read_next_queued_job(session=async_session)
processed = queued_job is not None
if queued_job is not None:
await advance_job(job=queued_job, services=services, session=async_session)
job = await async_session.get(Job, upload_result.job_id)
assert processed is True
+10 -2
View File
@@ -1,4 +1,7 @@
from uuid import uuid4
from datetime import UTC
from datetime import datetime
from datetime import timedelta
import pytest
@@ -100,8 +103,13 @@ class TestJobService:
document = Document(id=uuid4(), name="ordered-doc")
await document_service.create_document(document=document)
first = Job(document_id=document.id, status=JobStatus.QUEUED)
second = Job(document_id=document.id, status=JobStatus.QUEUED)
created_at = datetime.now(UTC)
first = Job(document_id=document.id, status=JobStatus.QUEUED, date_created=created_at)
second = Job(
document_id=document.id,
status=JobStatus.QUEUED,
date_created=created_at + timedelta(microseconds=1),
)
await job_service.create_job(job=first)
await job_service.create_job(job=second)
+30 -24
View File
@@ -30,8 +30,7 @@ class TestDocumentsPageRendering:
assert response.status_code == 200
assert "Documents" in response.text
assert "Create new document" in response.text
assert "No documents yet." in response.text
assert "Create your first document" in response.text
assert "No documents in repository yet." in response.text
def test_document_create_page_renders_fields(self, app_client):
"""GET /ui/documents/new renders document-create form fields."""
@@ -40,7 +39,7 @@ class TestDocumentsPageRendering:
response = client.get("/ui/documents/new")
assert response.status_code == 200
assert "Create document" in response.text
assert "Create Document" in response.text
assert "Document name is required." in response.text
assert "Document name" in response.text
assert "Document type" in response.text
@@ -69,7 +68,7 @@ class TestDocumentsPageRendering:
assert response.status_code == 200
assert "Seeded Document" in response.text
assert "Type: letter" in response.text
assert "letter" in response.text
def test_document_detail_page_renders_metadata_and_empty_related_sections(self, app_client):
"""GET /ui/documents/{document_id} shows metadata and related empty states."""
@@ -97,24 +96,30 @@ class TestDocumentsPageRendering:
assert response.status_code == 200
assert "Zenna Letter" in response.text
assert "Document type: letter" in response.text
assert "Author: not set" in response.text
assert "Exact date: 1885-07-13" in response.text
assert "Approximate date: c. 1885" in response.text
assert "Location created: Ohio" in response.text
assert "Archive identifier: BOX-1-FOLDER-2" in response.text
assert "Notes: Family archive" in response.text
assert "Created at (read-only):" in response.text
assert "Updated at (read-only):" in response.text
assert "Type: letter" in response.text
assert "Author:" in response.text
assert "Not set" in response.text
assert "Exact Date:" in response.text
assert "1885-07-13" in response.text
assert "Approx. Date:" in response.text
assert "c. 1885" in response.text
assert "Location Created:" in response.text
assert "Ohio" in response.text
assert "Archive Identifier:" in response.text
assert "BOX-1-FOLDER-2" in response.text
assert "Archival Notes:" in response.text
assert "Family archive" in response.text
assert "Created:" in response.text
assert "Updated:" in response.text
assert "No linked people yet." in response.text
assert "0 source(s) linked" in response.text
assert "0 job(s) linked" in response.text
assert "0 Source(s) Linked" in response.text
assert "0 Active Jobs" in response.text
assert "+ Add Source" in response.text
assert "+ Add Job" in response.text
assert "Sources" in response.text
assert "Jobs" in response.text
assert "Edit document" in response.text
assert "Delete document" in response.text
assert "Edit Document" in response.text
assert "Delete" in response.text
def test_document_detail_page_renders_related_people_sources_and_jobs(self, app_client):
"""GET /ui/documents/{document_id} shows related records when present."""
@@ -158,10 +163,11 @@ class TestDocumentsPageRendering:
response = client.get(f"/ui/documents/{document_id}")
assert response.status_code == 200
assert "Jane Doe (author)" in response.text
assert "Author: Jane Doe" in response.text
assert "1 source(s) linked" in response.text
assert "1 job(s) linked" in response.text
assert "Jane Doe" in response.text
assert "author" in response.text
assert "Author:" in response.text
assert "1 Source(s) Linked" in response.text
assert "1 Active Jobs" in response.text
def test_document_jobs_page_filters_to_document_context(self, app_client):
_, client = app_client
@@ -223,7 +229,7 @@ class TestDocumentsPageRendering:
response = client.get(f"/ui/sources?document_id={document_id}")
assert response.status_code == 200
assert "Sources for Target" in response.text
assert "Sources: Target" in response.text
assert "Back to Document" in response.text
assert "target_page.png" in response.text
assert "other_page.png" not in response.text
@@ -267,7 +273,7 @@ class TestDocumentsPageRendering:
response = client.get(f"/ui/documents/{document_id}/edit")
assert response.status_code == 200
assert "Edit document" in response.text
assert "Edit Document Record" in response.text
assert "Document name and document type are required." in response.text
assert "Document name" in response.text
assert "Document type" in response.text
@@ -298,7 +304,7 @@ class TestDocumentsPageRendering:
response = client.get(f"/ui/documents/{document_id}/delete")
assert response.status_code == 200
assert "Delete document" in response.text
assert "Delete Document" in response.text
assert "This action permanently deletes the document." in response.text
assert "Delete document permanently" in response.text
+6 -6
View File
@@ -21,7 +21,7 @@ class TestPageRendering:
assert response.status_code == 200
assert "Create job" in response.text
assert "No jobs yet." in response.text
assert "No active or historical processing jobs found." in response.text
def test_job_create_page_requires_existing_documents(self, app_client):
"""GET /ui/jobs/new shows guidance when no Documents exist."""
@@ -30,7 +30,7 @@ class TestPageRendering:
response = client.get("/ui/jobs/new")
assert response.status_code == 200
assert "Create job" in response.text
assert "Create Processing Job" in response.text
assert "No documents available. Create a Document before creating a Job." in response.text
assert "Create document" in response.text
@@ -48,7 +48,7 @@ class TestPageRendering:
response = client.get("/ui/jobs/new")
assert response.status_code == 200
assert "Create job" in response.text
assert "Create Processing Job" in response.text
assert "Seeded Document" in response.text
assert "Files are processed alphabetically by original filename." in response.text
assert "No files uploaded yet." in response.text
@@ -81,9 +81,9 @@ class TestPageRendering:
assert "Provider:" in response.text
assert "Model:" in response.text
assert "Prompt:" in response.text
assert "Retry count:" in response.text
assert "Last updated:" in response.text
assert "Document Links" in response.text
assert "Retry Count:" in response.text
assert "Last Updated:" in response.text
assert "document links" in response.text.lower()
assert "Sources" in response.text
assert "Jobs" in response.text
assert "Delete job" not in response.text
+19 -17
View File
@@ -25,7 +25,7 @@ class TestPeoplePageRendering:
assert response.status_code == 200
assert "People" in response.text
assert "Create new person" in response.text
assert "No people yet." in response.text
assert "No person records found in repository." in response.text
def test_people_page_lists_seeded_people(self, app_client):
_, client = app_client
@@ -41,7 +41,7 @@ class TestPeoplePageRendering:
assert response.status_code == 200
assert "Ada Lovelace" in response.text
assert "Display name: Ada" in response.text
assert "Ada" in response.text
def test_person_create_page_renders_fields(self, app_client):
_, client = app_client
@@ -49,7 +49,7 @@ class TestPeoplePageRendering:
response = client.get("/ui/people/new")
assert response.status_code == 200
assert "Create person" in response.text
assert "Create Person Record" in response.text
assert "Full name is required." in response.text
assert "Birth date (YYYY-MM-DD)" in response.text
assert "Death date (YYYY-MM-DD)" in response.text
@@ -85,15 +85,17 @@ class TestPeoplePageRendering:
assert response.status_code == 200
assert "Grace Hopper" in response.text
assert "Full name: Grace Hopper" in response.text
assert "Display name: Grace" in response.text
assert "Maiden name: Murray" in response.text
assert "Birth date: 1906-12-09" in response.text
assert "Death date: 1992-01-01" in response.text
assert "Biography: Computer pioneer" in response.text
assert "Portrait path: /images/grace.jpg" in response.text
assert "Created at (read-only):" in response.text
assert "Updated at (read-only):" in response.text
assert "Full Name:" in response.text
assert "Display Name:" in response.text
assert "Maiden Name:" in response.text
assert "Birth Date:" in response.text
assert "1906-12-09" in response.text
assert "Death Date:" in response.text
assert "1992-01-01" in response.text
assert "biography" in response.text.lower()
assert "Computer pioneer" in response.text
assert "Created:" in response.text
assert "Updated:" in response.text
assert "No linked documents yet." in response.text
assert "Link this person from a Document workflow." in response.text
@@ -115,7 +117,6 @@ class TestPeoplePageRendering:
response = client.get(f"/ui/people/{person_id}")
assert response.status_code == 200
assert "Portrait path: portraits/person/seeded.png" in response.text
assert "/uploads/portraits/person/seeded.png" in response.text
def test_person_detail_page_renders_linked_documents(self, app_client):
@@ -145,7 +146,8 @@ class TestPeoplePageRendering:
response = client.get(f"/ui/people/{person_id}")
assert response.status_code == 200
assert "Linked Document (author)" in response.text
assert "Linked Document" in response.text
assert "Role: author" in response.text
def test_person_detail_page_handles_invalid_id(self, app_client):
_, client = app_client
@@ -179,7 +181,7 @@ class TestPeoplePageRendering:
response = client.get(f"/ui/people/{person_id}/edit")
assert response.status_code == 200
assert "Edit person" in response.text
assert "Edit Person Record" in response.text
assert "Full name is required." in response.text
assert "Full name" in response.text
assert "Save changes" in response.text
@@ -200,8 +202,8 @@ class TestPeoplePageRendering:
response = client.get(f"/ui/people/{person_id}/delete")
assert response.status_code == 200
assert "Delete person" in response.text
assert "This action permanently deletes the person." in response.text
assert "Delete Person Record" in response.text
assert "This action permanently deletes the person record." in response.text
assert "Delete person permanently" in response.text
def test_person_delete_page_shows_blocked_state_when_linked_documents_exist(self, app_client):
+8 -11
View File
@@ -23,7 +23,7 @@ class TestSourcesPageRendering:
assert response.status_code == 200
assert "Sources" in response.text
assert "No sources added yet." in response.text
assert "No source file records found." in response.text
def test_sources_page_lists_seeded_sources(self, app_client):
_, client = app_client
@@ -49,9 +49,8 @@ class TestSourcesPageRendering:
response = client.get("/ui/sources")
assert response.status_code == 200
assert "Page 1: page_one.png" in response.text
assert "page_one.png" in response.text
assert "stored_page_one.png" in response.text
assert "Open source detail" in response.text
def test_sources_page_filters_to_document_context(self, app_client):
_, client = app_client
@@ -90,11 +89,10 @@ class TestSourcesPageRendering:
response = client.get(f"/ui/sources?document_id={document_id}")
assert response.status_code == 200
assert "Sources for Target" in response.text
assert "Sources: Target" in response.text
assert "Back to Document" in response.text
assert "target_page.png" in response.text
assert "other_page.png" not in response.text
assert "Open source detail" in response.text
def test_sources_page_filters_to_job_context(self, app_client, seed_job):
_, client = app_client
@@ -106,7 +104,6 @@ class TestSourcesPageRendering:
assert "Sources for Job" in response.text
assert "Back to Job" in response.text
assert "job-page.png" in response.text
assert "Open source detail" in response.text
def test_source_detail_page_renders_preview_and_revision_box(self, app_client, seed_job):
_, client = app_client
@@ -133,11 +130,11 @@ class TestSourcesPageRendering:
response = client.get(f"/ui/sources/{source_id}")
assert response.status_code == 200
assert "Source detail-source.png" in response.text
assert "Source Page 1: detail-source.png" in response.text
assert "Back to Sources" in response.text
assert "Transcription text" in response.text
assert "automated raw transcription" in response.text.lower()
assert "original transcription text" in response.text
assert "Revision text" in response.text
assert "curated human transcription" in response.text.lower()
assert "human revision text" in response.text
assert "Page number:" in response.text
assert "Stored filename:" in response.text
assert "Page Number:" in response.text
assert "Stored Filename:" in response.text