From 06c37f89b017734bd9b2671ffdcfe14a03125e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Fri, 8 May 2026 05:07:19 -0400 Subject: [PATCH] Track tab opener relationships --- crates/ely_browser_core/src/state/tabs.rs | 1 + crates/ely_browser_core/tests/tabs.rs | 34 +++++++++++++++++++++++ crates/ely_domain/src/tab.rs | 13 +++++++++ 3 files changed, 48 insertions(+) diff --git a/crates/ely_browser_core/src/state/tabs.rs b/crates/ely_browser_core/src/state/tabs.rs index 096e73f..dde3720 100644 --- a/crates/ely_browser_core/src/state/tabs.rs +++ b/crates/ely_browser_core/src/state/tabs.rs @@ -322,6 +322,7 @@ impl BrowserCore { fn build_tab(&self, url: UrlText) -> BrowserTab { self.build_tab_for(self.active_space_id.clone(), self.active_profile_id.clone(), url) + .with_parent_tab_id(self.active_tab_id.clone()) } pub(super) fn nearest_tab_in_space( diff --git a/crates/ely_browser_core/tests/tabs.rs b/crates/ely_browser_core/tests/tabs.rs index 9a1174d..31fc06f 100644 --- a/crates/ely_browser_core/tests/tabs.rs +++ b/crates/ely_browser_core/tests/tabs.rs @@ -22,6 +22,40 @@ fn opens_new_tab_below_active_tab() -> Result<(), Box> { Ok(()) } +#[test] +fn opened_tabs_record_active_tab_as_parent() -> Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + let first_tab_id = core.active_tab()?.id().clone(); + + let second_tab_id = core.open_tab(UrlText::parse("https://example.com")?); + let snapshot = core.snapshot()?; + + let opened_tab = snapshot + .tabs + .iter() + .find(|tab| tab.id() == &second_tab_id) + .ok_or(CoreError::MissingActiveTab)?; + assert_eq!(opened_tab.parent_tab_id(), Some(&first_tab_id)); + Ok(()) +} + +#[test] +fn replacement_tabs_have_no_parent_tab() -> Result<(), Box> { + let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; + let active_tab_id = core.active_tab()?.id().clone(); + + let replacement_tab_id = core.close_tab(&active_tab_id)?; + let snapshot = core.snapshot()?; + + let replacement_tab = snapshot + .tabs + .iter() + .find(|tab| tab.id() == &replacement_tab_id) + .ok_or(CoreError::MissingActiveTab)?; + assert_eq!(replacement_tab.parent_tab_id(), None); + Ok(()) +} + #[test] fn closes_active_tab_and_selects_next_neighbor() -> Result<(), Box> { let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?; diff --git a/crates/ely_domain/src/tab.rs b/crates/ely_domain/src/tab.rs index 04223b8..3621770 100644 --- a/crates/ely_domain/src/tab.rs +++ b/crates/ely_domain/src/tab.rs @@ -26,6 +26,7 @@ pub struct BrowserTab { profile_id: ProfileId, title: String, url: UrlText, + parent_tab_id: Option, state: TabState, flags: TabFlags, split_id: Option, @@ -49,6 +50,7 @@ impl BrowserTab { profile_id, title: title.into(), url, + parent_tab_id: None, state: TabState::Ready, flags: TabFlags::default(), split_id: None, @@ -57,6 +59,12 @@ impl BrowserTab { } } + #[must_use] + pub fn with_parent_tab_id(mut self, parent_tab_id: TabId) -> Self { + self.parent_tab_id = Some(parent_tab_id); + self + } + #[must_use] pub fn id(&self) -> &TabId { &self.id @@ -82,6 +90,11 @@ impl BrowserTab { &self.url } + #[must_use] + pub fn parent_tab_id(&self) -> Option<&TabId> { + self.parent_tab_id.as_ref() + } + #[must_use] pub fn display_url(&self) -> String { self.url.display_url()