From 141ee1fa8582f0aad9fb8038d93bf838e901366e Mon Sep 17 00:00:00 2001 From: Jim Lancaster <40281233+zoltan57@users.noreply.github.com> Date: Sun, 23 Aug 2026 10:49:40 -0500 Subject: [PATCH] V5.0 Minor change to UI --- docs/ui/pages/documents.md | 2 +- .../ui/components/table/documents.py | 33 ++++++++++++------- src/transcription/ui/pages/documents_page.py | 14 +++++++- tests/ui/test_documents_page.py | 20 ++++++++++- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/docs/ui/pages/documents.md b/docs/ui/pages/documents.md index 238bf83..5fb4918 100644 --- a/docs/ui/pages/documents.md +++ b/docs/ui/pages/documents.md @@ -22,7 +22,7 @@ Documents manages the archival record for each historical artifact independently - The title is **Archival Documents**. - **Create new document** opens the create route. - The table defaults to Document Title order and supports search and column sorting. -- Columns are Document Title, Type, Author, Document Date, and # Sources. +- Columns are Document Title, Author, Tags, Document Date, Type, and # Sources. - Document Title is left-aligned; the remaining columns are centered. - Author lists all linked people in the `author` role. - # Sources reflects the count of linked Source rows for each Document. diff --git a/src/transcription/ui/components/table/documents.py b/src/transcription/ui/components/table/documents.py index a401814..9e8fdc7 100644 --- a/src/transcription/ui/components/table/documents.py +++ b/src/transcription/ui/components/table/documents.py @@ -22,6 +22,7 @@ class DocumentTableRow: name: str document_type: str authors: str + tags: str document_date: str source_count: int @@ -33,6 +34,7 @@ def _serialize_rows(rows: Sequence[DocumentTableRow]) -> list[dict[str, Any]]: "name": row.name, "document_type": row.document_type or "Unspecified", "authors": row.authors or "Not set", + "tags": row.tags or "Not tagged", "document_date": row.document_date, "source_count": row.source_count, } @@ -59,15 +61,6 @@ def render_documents_table(rows: Sequence[DocumentTableRow]) -> None: "align": "left", "style": "width: 30%;", }, - { - "name": "document_type", - "label": "Type", - "field": "document_type", - "sortable": True, - "classes": "ui-table-cell-wrap", - "align": "center", - "style": "width: 14%;", - }, { "name": "authors", "label": "Author", @@ -75,7 +68,16 @@ def render_documents_table(rows: Sequence[DocumentTableRow]) -> None: "sortable": True, "classes": "ui-table-cell-wrap", "align": "center", - "style": "width: 22%;", + "style": "width: 18%;", + }, + { + "name": "tags", + "label": "Tags", + "field": "tags", + "sortable": True, + "classes": "ui-table-cell-wrap", + "align": "center", + "style": "width: 16%;", }, { "name": "document_date", @@ -86,6 +88,15 @@ def render_documents_table(rows: Sequence[DocumentTableRow]) -> None: "align": "center", "style": "width: 14%;", }, + { + "name": "document_type", + "label": "Type", + "field": "document_type", + "sortable": True, + "classes": "ui-table-cell-wrap", + "align": "center", + "style": "width: 12%;", + }, { "name": "source_count", "label": "# Sources", @@ -93,7 +104,7 @@ def render_documents_table(rows: Sequence[DocumentTableRow]) -> None: "sortable": True, "classes": "font-mono", "align": "center", - "style": "width: 20%;", + "style": "width: 10%;", }, ], default_sort_by="name", diff --git a/src/transcription/ui/pages/documents_page.py b/src/transcription/ui/pages/documents_page.py index dd3932e..a912474 100644 --- a/src/transcription/ui/pages/documents_page.py +++ b/src/transcription/ui/pages/documents_page.py @@ -193,9 +193,10 @@ def register_page() -> None: # noqa: PLR0915 DocumentTableRow( id=doc.id, name=doc.name, - document_type=(doc.document_type_ref.label if doc.document_type_ref is not None else ""), authors=", ".join(_author_names(doc)), + tags=", ".join(_tag_labels(doc)), document_date=compact_date(doc.document_date, doc.document_date_raw), + document_type=(doc.document_type_ref.label if doc.document_type_ref is not None else ""), source_count=len(doc.sources), ) for doc in documents @@ -628,6 +629,17 @@ def _author_names(document: Document) -> list[str]: ) +def _tag_labels(document: Document) -> list[str]: + return sorted( + ( + link.tag_ref.label + for link in document.document_tags + if link.tag_ref is not None and link.tag_ref.label.strip() + ), + key=str.casefold, + ) + + def _resolve_selected_tag_labels(value: object) -> list[str]: def flatten(item: object) -> list[str]: if item is None: diff --git a/tests/ui/test_documents_page.py b/tests/ui/test_documents_page.py index 611507b..9f04d11 100644 --- a/tests/ui/test_documents_page.py +++ b/tests/ui/test_documents_page.py @@ -1,6 +1,7 @@ """Tests for the documents page routes and action handlers.""" from datetime import date +import re import pytest import pytest_asyncio @@ -13,6 +14,8 @@ from transcription.db.models import DocumentType from transcription.db.models import Job from transcription.db.models import Person from transcription.db.models import PersonRole +from transcription.db.models import Tag +from transcription.db.models import DocumentTag from transcription.db.models import Source from transcription.ui.pages.documents_page import _resolve_selected_tag_labels @@ -69,12 +72,15 @@ class TestDocumentsPageRendering: async with session_scope() as session: postcard_type = (await session.exec(select(DocumentType).where(DocumentType.label == "Postcard"))).one() + family_tag = Tag(label="Family", normalized_label="family") doc = Document( name="1924 Postcard", document_type_id=postcard_type.id, archive_identifier="PC-001", ) - session.add(doc) + session.add_all([doc, family_tag]) + await session.flush() + session.add(DocumentTag(document_id=doc.id, tag_id=family_tag.id)) await session.commit() response = client.get("/ui/documents") @@ -84,8 +90,20 @@ class TestDocumentsPageRendering: assert "Postcard" in response.text assert "Document Date" in response.text assert "Author" in response.text + assert "Tags" in response.text + assert "Family" in response.text assert "# Sources" in response.text assert "Archive Ref" not in response.text + assert re.search( + r'"name":"name","label":"Document Title".*' + r'"name":"authors","label":"Author".*' + r'"name":"tags","label":"Tags".*' + r'"name":"document_date","label":"Document Date".*' + r'"name":"document_type","label":"Type".*' + r'"name":"source_count","label":"# Sources"', + response.text, + re.DOTALL, + ) def test_document_create_page_renders_form(self, app_client): _, client = app_client