diff --git a/ears/board.py b/ears/board.py index 5633a21..5c57e05 100644 --- a/ears/board.py +++ b/ears/board.py @@ -106,7 +106,13 @@ def render_page(snapshot, theme, headline, stale, fresh_until, attention, unknow work_links.append({"label": repository, "href": "https://github.com/" + repository}) checkin = theme.portable_prompt(CHECKIN) body.append(theme.orchestration_panel("ears", "", "", CHECKIN, - work_links=work_links, copy_label="Copy community check-in", organ="ears")) + work_links=work_links, copy_label="Copy community check-in", organ="ears", + refreshed_at=(snapshot.get("generated") + if any(r["status"] == "complete" for r in receipts) + and all(r["status"] in {"complete", "excluded"} for r in receipts) + else None), + refresh_url=(f"https://github.com/{repository}/actions/workflows/pages.yml" + if re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", repository) else None))) md = ['# PyAutoEars', '', headline, '', '## Community check-in', '', '```text', checkin, '```', ''] def section(title, key, selected, empty): diff --git a/tests/board_browser.py b/tests/board_browser.py index 41e46d9..8243518 100644 --- a/tests/board_browser.py +++ b/tests/board_browser.py @@ -47,7 +47,10 @@ def main(): assert not page.evaluate("document.documentElement.scrollWidth > innerWidth"), (width, scheme) page.screenshot(path=str(output / f"synthetic-{width}-{scheme}.png"), full_page=True) assert not page.locator('#freshness').is_visible() - assert page.locator('.orchestration-panel a').count() == 2 + assert page.locator('.orchestration-links a').count() == 2 + update = page.locator('.orchestration-panel [data-refresh-link]') + assert update.count() == 1 + assert update.get_attribute('href') == f"https://github.com/{CONFIG['repo']}/actions/workflows/pages.yml" assert page.locator('#unknown, #follow-through').count() == 0 for link in page.locator('a[href^="#"]').all(): assert page.locator(link.get_attribute('href')).count() == 1 diff --git a/tests/test_ears.py b/tests/test_ears.py index 7995367..8eef022 100644 --- a/tests/test_ears.py +++ b/tests/test_ears.py @@ -217,3 +217,27 @@ def test_bot_pr_requested_review_is_not_lost(): api = API({listing(): [pr], "repos/example/lib/pulls/1": {"requested_reviewers": [user("Second")]}}) row = collect.collect(api, ["example/lib"], CONFIG)["conversations"][0] assert row["review_requested"] is True and row["awaiting_response"] is False + + +def test_panel_refresh_uses_snapshot_capture_and_owner_workflow(monkeypatch): + theme = board.presentation(BRAIN)[0] + calls = [] + monkeypatch.setattr(theme, "orchestration_panel", lambda *a, **kw: calls.append(kw) or "") + monkeypatch.setattr(board, "presentation", lambda brain: (theme, board.load_module(BRAIN / "board/_state.py", "freshness_state"))) + snap = fixture() + board.render(snap, CONFIG, BRAIN, rendered_at="2026-10-07T12:00:00Z") + assert calls[0]["refreshed_at"] == snap["generated"] + assert calls[0]["refresh_url"] == f"https://github.com/{CONFIG['repo']}/actions/workflows/pages.yml" + + for status in ("partial", "unavailable"): + snap["receipts"][0]["status"] = status + board.render(snap, CONFIG, BRAIN, rendered_at=STAMP) + assert calls[-1]["refreshed_at"] is None + for receipt in snap["receipts"]: + receipt["status"] = "excluded" + board.render(snap, CONFIG, BRAIN, rendered_at=STAMP) + assert calls[-1]["refreshed_at"] is None + snap["receipts"] = [] + snap["conversations"] = [] + board.render(snap, CONFIG, BRAIN, rendered_at=STAMP) + assert calls[-1]["refreshed_at"] is None diff --git a/tests/test_presentation.py b/tests/test_presentation.py index 51d1a95..93f9911 100644 --- a/tests/test_presentation.py +++ b/tests/test_presentation.py @@ -129,7 +129,9 @@ def test_shared_checkin_keeps_public_destinations_and_inert_payload(): page = board.render(snapshot, CONFIG, BRAIN, rendered_at=STAMP)['index.html'] panel = re.search(r'
', page, re.S)[0] assert 'https://github.com/private/unknown' not in panel - assert len(re.findall(r'