generated from john/python-template
@@ -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.
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user