From e6a0603fc3215d9b2b5cd052c5c2439d573391a5 Mon Sep 17 00:00:00 2001 From: Jason Walker <913443@dadeschools.net> Date: Tue, 7 Jul 2026 16:07:20 -0400 Subject: [PATCH] fix: hide empty-state copy on queue credential fail-closed (Closes #458) When fetch_error is set, render only the unavailable banner and an explicit not-fetched inventory note. Suppress queue tables, pagination proof, and "No open items." copy that implied a successful empty fetch. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_webui_queue_dashboard.py | 31 +++++++++++++++++++++++++++++ webui/queue_views.py | 13 +++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/tests/test_webui_queue_dashboard.py b/tests/test_webui_queue_dashboard.py index cc9ea97..9fe3459 100644 --- a/tests/test_webui_queue_dashboard.py +++ b/tests/test_webui_queue_dashboard.py @@ -209,6 +209,37 @@ class TestQueueRoutes(unittest.TestCase): self.assertIsNotNone(snapshot.fetch_error) self.assertEqual(len(snapshot.prs), 0) + def test_queue_fail_closed_hides_empty_state_copy(self): + with mock.patch("webui.queue_loader.get_auth_header", return_value=None): + snapshot = load_queue_snapshot() + with mock.patch("webui.app.load_queue_snapshot", return_value=snapshot): + response = self.client.get("/queue") + self.assertEqual(response.status_code, 200) + self.assertIn("Queue unavailable", response.text) + self.assertIn("not fetched", response.text.lower()) + self.assertNotIn("No open items.", response.text) + self.assertNotIn("Open pull requests", response.text) + self.assertNotIn("pages_fetched", response.text) + + def test_queue_successful_empty_inventory_shows_empty_state(self): + def _empty_prs(*_args, **_kwargs): + return [], _mock_pagination(0) + + def _empty_issues(*_args, **_kwargs): + return [], _mock_pagination(0) + + snapshot = load_queue_snapshot( + fetch_prs=_empty_prs, + fetch_issues=_empty_issues, + ) + with mock.patch("webui.app.load_queue_snapshot", return_value=snapshot): + response = self.client.get("/queue") + self.assertEqual(response.status_code, 200) + self.assertIsNone(snapshot.fetch_error) + self.assertEqual(response.text.count("No open items."), 2) + self.assertIn("pages_fetched", response.text) + self.assertIn("pagination (complete)", response.text) + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/webui/queue_views.py b/webui/queue_views.py index 8294b8e..becf346 100644 --- a/webui/queue_views.py +++ b/webui/queue_views.py @@ -72,6 +72,18 @@ def render_queue_page(snapshot: QueueSnapshot) -> str: f'

Queue unavailable: ' f"{html.escape(snapshot.fetch_error)}

" ) + inventory_block = ( + "

Inventory: not fetched " + "(fail closed — queue tables omitted).

" + ) + return ( + "

Live queue

" + f"

Repository: {html.escape(snapshot.repo_label)} " + f"· project {html.escape(snapshot.project_id)}

" + f"{error_block}" + f"{inventory_block}" + "

Read-only MVP — claims, reviews, and merges stay in Gitea/MCP tools.

" + ) pr_section = _queue_table( title="Open pull requests", @@ -101,7 +113,6 @@ def render_queue_page(snapshot: QueueSnapshot) -> str: "

Live queue

" f"

Repository: {html.escape(snapshot.repo_label)} " f"· project {html.escape(snapshot.project_id)}

" - f"{error_block}" f"{_pagination_html('PR', snapshot.pr_pagination)}" f"{pr_section}" f"{_pagination_html('Issue', snapshot.issue_pagination)}"