feat: add review requests to My Work (#117)
This commit is contained in:
1 parent
26ffa1f1b3
commit
b7d4bd8137
7 files changed
+116
-14
No files matched your search
@@ -6,7 +6,7 @@ from src import main
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_work_collections_use_supported_assigned_search_endpoint(monkeypatch):
|
||||
async def test_work_collections_include_supported_review_request_search(monkeypatch):
|
||||
requested_paths = []
|
||||
|
||||
async def fake_fetch(path):
|
||||
@@ -20,9 +20,39 @@ async def test_work_collections_use_supported_assigned_search_endpoint(monkeypat
|
||||
assert requested_paths == [
|
||||
"repos/issues/search?state=open&assigned=true&type=issues&limit=50",
|
||||
"repos/issues/search?state=open&assigned=true&type=pulls&limit=50",
|
||||
"repos/issues/search?state=open&review_requested=true&type=pulls&limit=50",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_pull_requests_merge_assignment_and_review_responsibilities(monkeypatch):
|
||||
assigned = {
|
||||
"id": 11,
|
||||
"number": 7,
|
||||
"title": "Review API",
|
||||
"repository": {"full_name": "stackchain/api"},
|
||||
}
|
||||
review_only = {
|
||||
"id": 12,
|
||||
"number": 8,
|
||||
"title": "Review mobile",
|
||||
"repository": {"full_name": "stackchain/mobile"},
|
||||
}
|
||||
|
||||
async def fake_fetch(path):
|
||||
if "assigned=true" in path:
|
||||
return [assigned]
|
||||
return [assigned.copy(), review_only]
|
||||
|
||||
monkeypatch.setattr(gitea_proxy, "fetch", fake_fetch)
|
||||
|
||||
pulls = await gitea_proxy.pull_requests()
|
||||
|
||||
assert [pull["id"] for pull in pulls] == [11, 12]
|
||||
assert pulls[0]["work_reasons"] == ["assigned_to_me", "review_requested"]
|
||||
assert pulls[1]["work_reasons"] == ["review_requested"]
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_context_preserves_repository_and_update_time_for_cross_repo_work(monkeypatch):
|
||||
async def user():
|
||||
@@ -53,6 +83,7 @@ async def test_context_preserves_repository_and_update_time_for_cross_repo_work(
|
||||
"user": {"login": "alex"},
|
||||
"labels": [{"name": "priority-high"}],
|
||||
"assignees": [{"login": "timmy"}],
|
||||
"work_reasons": ["assigned_to_me", "review_requested"],
|
||||
"repository": {"full_name": "stackchain/api"},
|
||||
"updated_at": "2026-08-06T11:00:00Z",
|
||||
"html_url": "https://forge.example/stackchain/api/pulls/7",
|
||||
@@ -71,3 +102,7 @@ async def test_context_preserves_repository_and_update_time_for_cross_repo_work(
|
||||
assert payload["pull_requests"][0]["updated_at"] == "2026-08-06T11:00:00Z"
|
||||
assert payload["pull_requests"][0]["labels"] == ["priority-high"]
|
||||
assert payload["pull_requests"][0]["assignees"] == ["timmy"]
|
||||
assert payload["pull_requests"][0]["work_reasons"] == [
|
||||
"assigned_to_me",
|
||||
"review_requested",
|
||||
]
|
||||
+32
-4
@@ -10,7 +10,7 @@ from src.views import dashboard
|
||||
MY_WORK = Path(__file__).parents[1] / "frontend" / "my-work.js"
|
||||
|
||||
|
||||
def test_my_work_queue_prioritizes_labels_then_assignment_and_keeps_repo_identity():
|
||||
def test_my_work_queue_prioritizes_labels_then_reviews_and_keeps_repo_identity():
|
||||
payload = {
|
||||
"user": {"login": "timmy"},
|
||||
"issues": [
|
||||
@@ -44,6 +44,7 @@ def test_my_work_queue_prioritizes_labels_then_assignment_and_keeps_repo_identit
|
||||
"title": "Review PR",
|
||||
"state": "open",
|
||||
"repository": "stackchain/web",
|
||||
"work_reasons": ["review_requested"],
|
||||
"updated_at": "2026-08-06T13:00:00Z",
|
||||
"url": "https://forge.example/web/pulls/4",
|
||||
}
|
||||
@@ -62,13 +63,38 @@ process.stdout.write(JSON.stringify(queue));
|
||||
|
||||
assert [item["title"] for item in queue] == [
|
||||
"Priority issue",
|
||||
"Assigned issue",
|
||||
"Review PR",
|
||||
"Assigned issue",
|
||||
]
|
||||
assert queue[0]["key"] == "stackchain/api#7"
|
||||
assert queue[0]["reason"] == "P0 priority"
|
||||
assert queue[1]["reason"] == "Assigned to you"
|
||||
assert queue[2]["kind"] == "pull"
|
||||
assert queue[1]["reason"] == "Needs your review"
|
||||
assert queue[1]["is_review"] is True
|
||||
assert queue[2]["reason"] == "Assigned to you"
|
||||
|
||||
|
||||
def test_my_work_reviews_filter_and_summary_are_actionable():
|
||||
items = [
|
||||
{"title": "Issue", "kind": "issue", "is_review": False, "is_assigned": True},
|
||||
{"title": "Assigned PR", "kind": "pull", "is_review": False, "is_assigned": True},
|
||||
{"title": "Review PR", "kind": "pull", "is_review": True, "is_assigned": False},
|
||||
]
|
||||
script = f"""
|
||||
const buildMyWork = require({json.dumps(str(MY_WORK))});
|
||||
const items = {json.dumps(items)};
|
||||
process.stdout.write(JSON.stringify({{
|
||||
reviews: buildMyWork.filterMyWork(items, 'review'),
|
||||
summary: buildMyWork.summarizeMyWork(items),
|
||||
}}));
|
||||
"""
|
||||
|
||||
result = subprocess.run(
|
||||
["node", "-e", script], check=True, capture_output=True, text=True
|
||||
)
|
||||
output = json.loads(result.stdout)
|
||||
|
||||
assert [item["title"] for item in output["reviews"]] == ["Review PR"]
|
||||
assert output["summary"] == "1 review · 2 assigned"
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
@@ -79,8 +105,10 @@ async def test_mobile_dashboard_puts_filterable_my_work_before_auxiliary_panels(
|
||||
assert 'data-work-filter="all"' in html
|
||||
assert 'data-work-filter="issue"' in html
|
||||
assert 'data-work-filter="pull"' in html
|
||||
assert 'data-work-filter="review"' in html
|
||||
assert '.work-filter' in html and 'min-height: 44px' in html
|
||||
assert '.my-work-card' in html and 'min-height: 44px' in html
|
||||
assert '<script src="static/my-work.js"></script>' in html
|
||||
assert "buildMyWork(data)" in html
|
||||
assert "markMyWorkStale()" in html
|
||||
assert "filterMyWork(lastMyWork, selectedWorkFilter)" in html
|
||||
Reference in new issue
Block a user