Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ title: Changelog
description: Release notes for aven.
---

## Unreleased

- Fix: Opening a [search](https://aventasks.dev/tui/#search-filter-and-order) result with `Enter` keeps the typed query as the committed search view, so closing the task detail returns to the full result list instead of a single-task view scoped to that task's reference.

## v0.1.43 (2026-09-26)

- Fix: Moving tasks or recurring schedules to a project now requires that project to exist in the selected workspace, preventing accidental duplicate projects. ([#29](https://github.com/raine/aven/issues/29))
Expand Down
14 changes: 10 additions & 4 deletions src/tui/app_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,16 @@ impl App {
) -> Result<()> {
match intent {
SearchIntent::Navigate => {
self.accept_search_input(result.display_ref.clone()).await?;
self.select_task_by_id(&result.task_id);
self.detail = crate::tui::detail_session::DetailSession::open(0);
self.show_detail(0);
self.accept_search_input(input).await?;
if self.select_task_by_id(&result.task_id) {
self.detail = crate::tui::detail_session::DetailSession::open(0);
self.show_detail(0);
} else {
// The picked result can be missing from the committed query
// results (e.g. the input changed after the preview ran);
// fall back to opening it as an exact task.
self.open_detail_task(&result.task_id, 0).await;
}
}
SearchIntent::AddDependency {
selection,
Expand Down
73 changes: 73 additions & 0 deletions src/tui/app_tests/typed_overlay_submissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,79 @@ async fn search_selected_blocker_adds_dependency() {
);
}

#[tokio::test]
async fn navigate_search_result_commits_typed_query() {
let mut app = test_app().await;
create_and_select_task(&mut app, test_task_draft("Needle one")).await;
let second = create_and_select_task(&mut app, test_task_draft("Needle two")).await;
let second_id = app.store.tasks[second].task.id.clone();

app.begin_search();
type_chars(&mut app, "needle").await;
settle_search_preview(&mut app).await;
let Some(OverlayState::Search(state)) = &mut app.overlay else {
panic!("expected search overlay");
};
state.selected = state
.results
.iter()
.position(|result| result.task_id == second_id)
.expect("picked task in preview results");
app.handle_overlay_key(key(KeyCode::Enter)).await.unwrap();

assert!(app.overlay.is_none());
assert!(app.detail.is_active());
assert_eq!(app.store.view_state.query, TaskQuery::Search);
assert!(matches!(
&app.store.view_state.projection_origin,
crate::tui::store::TaskProjectionOrigin::Search { query, .. } if query == "needle"
));
assert_eq!(app.store.tasks.len(), 2);
let selected = app.list.selected_task().unwrap();
assert_eq!(app.store.tasks[selected].task.id, second_id);
}

#[tokio::test]
async fn navigate_search_result_missing_from_results_opens_exact_task() {
let mut app = test_app().await;
create_and_select_task(&mut app, test_task_draft("Alpha target")).await;
let other = create_and_select_task(&mut app, test_task_draft("Beta other")).await;
let other_id = app.store.tasks[other].task.id.clone();

app.overlay = Some(OverlayState::Search(SearchState {
input: LineEdit::new("alpha".to_string()),
results: vec![crate::tui::overlay::SearchResultItem {
task_id: other_id.clone(),
display_ref: "BETA-REF".to_string(),
title: "Beta other".to_string(),
description: String::new(),
project_key: String::new(),
status: "inbox".to_string(),
priority: "none".to_string(),
created_at: String::new(),
labels: Vec::new(),
matched_field: crate::query::SearchMatchedField::Title,
snippet: None,
score: 0,
deleted: false,
is_epic: false,
unavailable_reason: None,
create_new: false,
}],
selected: 0,
total_matches: 1,
results_query: Some("alpha".to_string()),
intent: SearchIntent::Navigate,
}));
app.handle_overlay_key(key(KeyCode::Enter)).await.unwrap();

assert!(app.overlay.is_none());
assert!(app.detail.is_active());
assert_eq!(app.store.tasks.len(), 1);
assert_eq!(app.store.tasks[0].task.id, other_id);
assert_eq!(app.list.selected_task(), Some(0));
}

#[tokio::test]
async fn add_dependency_search_tab_keeps_picker_context() {
let mut app = test_app().await;
Expand Down
Loading