| 194 | 194 | | |
| 195 | 195 | | impl Wanted<'_> { |
| 196 | 196 | | fn admits(&self, session: &WorkspaceSession) -> bool { |
| 197 | + | self.admits_listed(session) && self.item.is_none_or(|item| session.item == Some(item)) |
| 198 | + | } |
| 199 | + | |
| 200 | + | /// For a row of the `sessions` table, which its query already chose by |
| 201 | + | /// work item, the session's own or one it is linked to |
| 202 | + | /// ([`workspace_sessions_sql`]): all but that. |
| 203 | + | fn admits_listed(&self, session: &WorkspaceSession) -> bool { |
| 197 | 204 | | self.shown.admits(session.state) |
| 198 | 205 | | && self.kind.is_none_or(|kind| kind == session.kind) |
| 199 | 206 | | && self.harness.is_none_or(|harness| session.harness == Some(harness)) |
| 200 | 207 | | && self.person.is_none_or(|person| session.actor.as_deref().is_some_and(|actor| actor.eq_ignore_ascii_case(person))) |
| 201 | | − | && self.item.is_none_or(|item| session.item == Some(item)) |
| 202 | 208 | | } |
| 203 | 209 | | } |
| 204 | 210 | | |
| ⋯ |
| 215 | 221 | | ) -> Vec<WorkspaceSession> { |
| 216 | 222 | | let covered: HashSet<(String, u32)> = |
| 217 | 223 | | sessions.iter().chain(&runs).filter_map(|session| session.pull.map(|pull| (session.repo_id.clone(), pull))).collect(); |
| 218 | | − | let mut all: Vec<WorkspaceSession> = sessions.into_iter().filter(|session| wanted.admits(session)).collect(); |
| 224 | + | let mut all: Vec<WorkspaceSession> = sessions.into_iter().filter(|session| wanted.admits_listed(session)).collect(); |
| 219 | 225 | | all.extend(runs.into_iter().filter(|run| wanted.admits(run))); |
| 220 | 226 | | all.extend( |
| 221 | 227 | | recorded |
| ⋯ |
| 711 | 717 | | } |
| 712 | 718 | | |
| 713 | 719 | | #[test] |
| 720 | + | fn a_session_linked_to_a_work_item_is_listed_for_it() { |
| 721 | + | // On no work item of its own, but linked to #12 (a claim, a trailer). |
| 722 | + | let session: Session = serde_json::from_value(serde_json::json!({ |
| 723 | + | "id": "ses_l", "repoId": "rep_api", "item": null, "pull": null, "branch": null, "actor": { "id": "usr_2", "username": "bo" }, |
| 724 | + | "harness": "codex", "harnessSessionId": null, "title": null, "state": "active", "headCommit": null, |
| 725 | + | "startedAt": at(5), "lastSeenAt": at(1), "endedAt": null, "endReason": null, "subagents": 0 |
| 726 | + | })) |
| 727 | + | .unwrap(); |
| 728 | + | let listed = from_session(session, "acme/api", NOW); |
| 729 | + | let for_item = Wanted { shown: SessionsShown::Recent, kind: None, harness: None, person: None, item: Some(12) }; |
| 730 | + | assert_eq!(merged(vec![listed], Vec::new(), Vec::new(), &for_item, 10).len(), 1); |
| 731 | + | } |
| 732 | + | |
| 733 | + | #[test] |
| 714 | 734 | | fn pull_facts_and_busy_queues_are_read_across_repositories() { |
| 715 | 735 | | let db = seeded(); |
| 716 | 736 | | let pairs = serde_json::json!([{ "r": "rep_web", "n": 9 }, { "r": "rep_api", "n": 7 }, { "r": "rep_api", "n": 99 }]).to_string(); |