From 34dd1419983329b4f8c61fdbd514f8463f6177ba Mon Sep 17 00:00:00 2001 From: "Sergei G." Date: Sat, 5 Sep 2026 10:43:39 +0400 Subject: [PATCH] story: replace List search results without duplicating rows Clear existing result groups before rebuilding them while keeping industry indices stable. Initialize groups and industry labels in sync so headings match their rows. Cover repeated, empty, cleared, and refreshed queries. --- crates/story/src/stories/list_story.rs | 74 +++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/crates/story/src/stories/list_story.rs b/crates/story/src/stories/list_story.rs index de7c411b4..e643c6f80 100644 --- a/crates/story/src/stories/list_story.rs +++ b/crates/story/src/stories/list_story.rs @@ -246,6 +246,9 @@ struct CompanyListDelegate { impl CompanyListDelegate { fn prepare(&mut self, query: impl Into) { self.query = query.into(); + for companies in &mut self.matched_companies { + companies.clear(); + } let companies: Vec> = self ._companies .iter() @@ -593,7 +596,7 @@ impl ListStory { fn new(window: &mut Window, cx: &mut Context) -> Self { let mut delegate = CompanyListDelegate { industries: vec![], - matched_companies: vec![vec![]], + matched_companies: vec![], _companies: vec![], selected_index: Some(IndexPath::default()), confirmed_index: None, @@ -809,3 +812,72 @@ impl Render for ListStory { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use core::prelude::v1::test; + + #[test] + fn searching_and_refreshing_replace_company_groups() { + let companies = [ + ("Acme", "Software"), + ("Books", "Retail"), + ("Atlas", "Software"), + ] + .into_iter() + .map(|(name, industry)| { + Rc::new(Company { + name: name.into(), + industry: industry.into(), + ..Company::default() + }) + }) + .collect(); + let mut delegate = CompanyListDelegate { + industries: vec![], + matched_companies: vec![], + _companies: companies, + selected_index: None, + confirmed_index: None, + query: "".into(), + loading: false, + eof: false, + lazy_load: false, + draggable: false, + drop_target: None, + }; + + for (query, expected) in [ + ("", vec![vec!["Acme", "Atlas"], vec!["Books"]]), + ("ACME", vec![vec!["Acme"], vec![]]), + ("missing", vec![vec![], vec![]]), + ("", vec![vec!["Acme", "Atlas"], vec!["Books"]]), + ] { + delegate.prepare(query); + assert_eq!(delegate.industries, vec!["Software", "Retail"]); + assert_eq!(delegate.matched_companies.len(), delegate.industries.len()); + let names: Vec> = delegate + .matched_companies + .iter() + .map(|companies| { + companies + .iter() + .map(|company| company.name.as_ref()) + .collect() + }) + .collect(); + assert_eq!(names, expected); + } + // Loading more data also rebuilds the current query; it must not duplicate old rows. + delegate.extend_more(0); + assert_eq!( + delegate + .matched_companies + .iter() + .map(Vec::len) + .sum::(), + 3 + ); + } +}