V4.11 Added tags + lots of little changes to the UI
Quality Gate / gate (push) Failing after 12s

This commit is contained in:
Jim Lancaster
2026-08-22 18:32:52 -05:00
parent 63c21d4a14
commit 0d554c0648
36 changed files with 932 additions and 116 deletions
+4
View File
@@ -23,6 +23,7 @@ from transcription.db import session as db_session_module
from transcription.db import session_scope
from transcription.db.models import Document
from transcription.db.models import DocumentPerson
from transcription.db.models import DocumentTag
from transcription.db.models import ExecutionAttempt
from transcription.db.models import Job
from transcription.db.models import JobSource
@@ -30,6 +31,7 @@ from transcription.db.models import JobSourceStatus
from transcription.db.models import JobStatus
from transcription.db.models import Person
from transcription.db.models import Source
from transcription.db.models import Tag
@pytest.fixture(scope="session")
@@ -73,11 +75,13 @@ async def clear_ui_database(
)
async with session_scope(session_factory=app.state.runtime.session_factory) as session:
await session.exec(delete(JobSource))
await session.exec(delete(DocumentTag))
await session.exec(delete(DocumentPerson))
await session.exec(delete(Source))
await session.exec(delete(Job))
await session.exec(delete(Document))
await session.exec(delete(Person))
await session.exec(delete(Tag))
await session.commit()
+11 -1
View File
@@ -14,6 +14,7 @@ from transcription.db.models import Job
from transcription.db.models import Person
from transcription.db.models import PersonRole
from transcription.db.models import Source
from transcription.ui.pages.documents_page import _resolve_selected_tag_labels
# --- Helper Fixtures ---
@@ -81,9 +82,10 @@ class TestDocumentsPageRendering:
assert response.status_code == 200
assert "1924 Postcard" in response.text
assert "Postcard" in response.text
assert "PC-001" in response.text
assert "Document Date" in response.text
assert "Author" in response.text
assert "# Sources" in response.text
assert "Archive Ref" not in response.text
def test_document_create_page_renders_form(self, app_client):
_, client = app_client
@@ -95,6 +97,7 @@ class TestDocumentsPageRendering:
assert "Document name" in response.text
assert "Linked People" in response.text
assert "Document type" in response.text
assert "Tags" in response.text
@pytest.mark.asyncio
async def test_document_create_page_preselects_person_with_disambiguating_label(self, app_client):
@@ -209,3 +212,10 @@ class TestDocumentsPageRendering:
assert "Delete Document" in response.text
assert "Delete document permanently" in response.text
assert "Delete is blocked" not in response.text
def test_resolve_selected_tag_labels_handles_multiple_payload_shapes():
assert _resolve_selected_tag_labels("Family") == ["Family"]
assert _resolve_selected_tag_labels(["Family", "Research"]) == ["Family", "Research"]
assert _resolve_selected_tag_labels([{"label": "Family"}, {"value": "Research"}]) == ["Family", "Research"]
assert set(_resolve_selected_tag_labels({"value": {"Family", "Research"}})) == {"Family", "Research"}
+3
View File
@@ -55,6 +55,7 @@ class TestJobsPageRendering:
assert response.status_code == 200
assert "Document Name" in response.text
assert "# Sources" in response.text
assert "Source Filename" not in response.text
assert "Updated" in response.text
assert "Created" not in response.text
@@ -112,6 +113,8 @@ class TestJobsPageRendering:
assert response.status_code == 200
assert "Create Processing Job" in response.text
assert "Preselected Journal Entry" in response.text
assert "Provider" in response.text
assert "Model" in response.text
@pytest.mark.asyncio
async def test_job_detail_page_renders_logistics_and_links(self, app_client, seed_document_with_unlinked_job):
+1
View File
@@ -28,6 +28,7 @@ class TestNavigationAndMounts:
"/ui/homepage",
"/ui/homepage/edit",
"/ui/documents",
"/ui/tags",
"/ui/people",
"/ui/sources",
"/ui/jobs",
+3
View File
@@ -16,6 +16,7 @@ class TestPageRegistration:
people_response = client.get("/ui/people")
sources_response = client.get("/ui/sources")
jobs_response = client.get("/ui/jobs")
tags_response = client.get("/ui/tags")
settings_response = client.get("/ui/settings")
assert homepage_response.status_code == 200
@@ -23,9 +24,11 @@ class TestPageRegistration:
assert people_response.status_code == 200
assert sources_response.status_code == 200
assert jobs_response.status_code == 200
assert tags_response.status_code == 200
assert settings_response.status_code == 200
assert "Document Types" in settings_response.text
assert "Person Roles" in settings_response.text
assert "Tags" in settings_response.text
assert "Prompts" in settings_response.text
assert "Home Page Text" in settings_response.text
assert "README.md" not in settings_response.text
+22 -1
View File
@@ -41,7 +41,28 @@ class TestPeoplePageRendering:
assert response.status_code == 200
assert "Ada Lovelace" in response.text
assert "Ada" in response.text
assert "FamilySearch ID" in response.text
assert "# Documents" in response.text
assert "Display Name" not in response.text
assert "Maiden Name" not in response.text
@pytest.mark.asyncio
async def test_people_page_shows_document_counts(self, app_client):
_, client = app_client
async with session_scope() as session:
role = (await session.exec(select(PersonRole).where(PersonRole.semantic_key == "author"))).one()
person = Person(full_name="Counted Person")
document = Document(name="Linked For Count")
session.add_all([person, document])
await session.flush()
session.add(DocumentPerson(document_id=document.id, person_id=person.id, role_id=role.id))
await session.commit()
response = client.get("/ui/people")
assert response.status_code == 200
assert '"document_count":1' in response.text
def test_person_create_page_renders_fields(self, app_client):
_, client = app_client
+1 -2
View File
@@ -261,9 +261,8 @@ class TestSourcesPageRendering:
assert "SOURCE PAGE 1: DETAIL-SOURCE.PNG" in response.text.upper()
assert "SOURCE METADATA" in response.text.upper()
assert "SOURCEJOB METADATA" in response.text.upper()
assert "TRANSCRIPTION TEXT" in response.text.upper()
assert "TRANSCRIPTION TEXT" not in response.text.upper()
assert "EDITABLE REVISION" in response.text.upper()
assert "original transcription text" in response.text
assert "human revision text" in response.text
assert "Save revision" in response.text
assert "Previous Page" in response.text
+43
View File
@@ -0,0 +1,43 @@
"""Tests for the tags page route and grouped filtering behavior."""
import pytest
from transcription.db import session_scope
from transcription.db.models import Document
from transcription.services.documents import DocumentService
@pytest.mark.integration
class TestTagsPageRendering:
def test_tags_page_renders_empty_state_without_tags(self, app_client):
_, client = app_client
response = client.get("/ui/tags")
assert response.status_code == 200
assert "Tags" in response.text
assert "No tags are configured yet." in response.text
@pytest.mark.asyncio
async def test_tags_page_groups_documents_by_tag(self, app_client):
app, client = app_client
documents = DocumentService(session_factory=app.state.runtime.session_factory)
async with session_scope(session_factory=app.state.runtime.session_factory) as session:
first = Document(name="Tagged Letter")
second = Document(name="Tagged Journal")
session.add_all([first, second])
await session.flush()
await documents.sync_document_tags_by_labels(document_id=first.id, labels=["Family"], session=session)
await documents.sync_document_tags_by_labels(
document_id=second.id,
labels=["Family", "Research"],
session=session,
)
await session.commit()
response = client.get("/ui/tags")
assert response.status_code == 200
assert "Filter by tag" in response.text
assert "Tags" in response.text