From 2083f57ea05a55caa649786c194f715119ea6565 Mon Sep 17 00:00:00 2001 From: Krzysztof Socha Date: Tue, 8 Sep 2026 06:41:16 +0200 Subject: [PATCH] Name who opened a ticket on the detail sidebar. Created and Updated were already facts; Created by was missing, so the row's creator_id never reached the page. Co-authored-by: Cursor --- .../contrib/software_factory/issues/pages.py | 12 ++++++++++ .../software_factory/test_issues_pages.py | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/backend/druks/contrib/software_factory/issues/pages.py b/backend/druks/contrib/software_factory/issues/pages.py index 83073254..9042c981 100644 --- a/backend/druks/contrib/software_factory/issues/pages.py +++ b/backend/druks/contrib/software_factory/issues/pages.py @@ -90,6 +90,12 @@ def _assignee_name(assignee_id: str | None, account_names: dict[str, str]) -> st return account_names.get(assignee_id, UNATTRIBUTED) +def _creator_name(creator_id: str | None, account_names: dict[str, str]) -> str: + if not creator_id: + return UNATTRIBUTED + return account_names.get(creator_id, UNATTRIBUTED) + + def _create_actions(repos: list[ProjectRepo], accounts: list[Account]) -> list[ui.Action]: """Creation is a control on the board and the issues page, not a destination: a page that lists nothing is not where a ticket gets written.""" @@ -546,6 +552,12 @@ async def ticket(identifier: str): ui.Facts( [ ui.Fact("Identifier", value=ui.TextValue(found.identifier)), + ui.Fact( + "Created by", + value=ui.TextValue( + _creator_name(found.creator_id, account_names) + ), + ), ui.Fact("Created", value=ui.TimeValue(found.created_at)), ui.Fact("Updated", value=ui.TimeValue(found.updated_at)), ] diff --git a/backend/tests/software_factory/test_issues_pages.py b/backend/tests/software_factory/test_issues_pages.py index f4ab2b5e..0d42e8b2 100644 --- a/backend/tests/software_factory/test_issues_pages.py +++ b/backend/tests/software_factory/test_issues_pages.py @@ -1,3 +1,4 @@ +from druks.accounts.models import Account from druks.contrib.software_factory.issues.models import Ticket from software_factory.factories import make_test_work_item @@ -194,6 +195,18 @@ async def test_ticket_page_follows_the_row_and_comments_refresh_the_region(druks repo = columns["blocks"][1]["blocks"][3] assert repo["fields"][0]["name"] == "repo_id" assert repo["fields"][0]["options"][0]["group"] == "Acme" + facts = columns["blocks"][1]["blocks"][-1] + assert [fact["label"] for fact in facts["facts"]] == [ + "Identifier", + "Created by", + "Created", + "Updated", + ] + assert facts["facts"][0]["value"]["text"] == created["identifier"] + account = await Account.get_or_create("op@example.com") + assert facts["facts"][1]["value"]["text"] == account.username + assert facts["facts"][2]["value"]["value"] == "time" + assert facts["facts"][3]["value"]["value"] == "time" comments = _comments(page) assert comments["title"] == "Comments" assert comments["blocks"][0]["title"] == "No comments yet" @@ -212,6 +225,17 @@ async def test_ticket_page_follows_the_row_and_comments_refresh_the_region(druks assert thread["blocks"][0]["blocks"][0]["text"] == "looks good" +async def test_ticket_page_unattributed_creator_when_none_is_stored(druks_client): + repo = await _open_repo(druks_client) + ticket = await Ticket.create(repo_id=int(repo["id"]), title="ghost") + + page = (await druks_client.get(f"{_PAGES}/tickets/{ticket.identifier}")).json() + + facts = page["blocks"][0]["blocks"][1]["blocks"][-1] + created_by = next(fact for fact in facts["facts"] if fact["label"] == "Created by") + assert created_by["value"]["text"] == "Unattributed" + + async def test_ticket_page_links_the_open_build(druks_client): repo = await _open_repo(druks_client) created = await _open_ticket(druks_client, repo["id"], title="Follow me")