Bind spaces to default profiles
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
use ely_browser_core::BrowserSnapshot;
|
use ely_browser_core::BrowserSnapshot;
|
||||||
use ely_design_system::colors;
|
use ely_design_system::colors;
|
||||||
use ely_domain::{ArchivePolicy, Space, SpaceId};
|
use ely_domain::{ArchivePolicy, Profile, Space, SpaceId};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString, Styled, div,
|
AnyElement, Context, InteractiveElement, IntoElement, ParentElement, SharedString, Styled, div,
|
||||||
px, rgb,
|
px, rgb,
|
||||||
@@ -109,13 +109,13 @@ fn render_active_space_summary(snapshot: &BrowserSnapshot) -> AnyElement {
|
|||||||
.text_color(rgb(colors::INK))
|
.text_color(rgb(colors::INK))
|
||||||
.child(active_space.name().to_string()),
|
.child(active_space.name().to_string()),
|
||||||
)
|
)
|
||||||
.child(div().text_xs().truncate().text_color(rgb(colors::MUTED)).child(
|
.child(
|
||||||
format!(
|
div()
|
||||||
"{} - {}",
|
.text_xs()
|
||||||
accent_label(active_space.accent_hex()),
|
.truncate()
|
||||||
archive_policy_label(active_space.archive_policy())
|
.text_color(rgb(colors::MUTED))
|
||||||
),
|
.child(space_detail_label(active_space, &snapshot.profiles)),
|
||||||
)),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(div().text_xs().font_semibold().text_color(rgb(colors::SUCCESS)).child("Active"))
|
.child(div().text_xs().font_semibold().text_color(rgb(colors::SUCCESS)).child("Active"))
|
||||||
@@ -132,7 +132,7 @@ fn render_spaces_list(snapshot: &BrowserSnapshot, cx: &mut Context<ElyShell>) ->
|
|||||||
.border_t_1()
|
.border_t_1()
|
||||||
.border_color(rgb(colors::HAIRLINE))
|
.border_color(rgb(colors::HAIRLINE))
|
||||||
.children(snapshot.spaces.iter().enumerate().map(|(index, space)| {
|
.children(snapshot.spaces.iter().enumerate().map(|(index, space)| {
|
||||||
render_space_row(index, space, space.id() == &snapshot.active_space_id, cx)
|
render_space_row(index, space, snapshot, space.id() == &snapshot.active_space_id, cx)
|
||||||
}))
|
}))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
@@ -140,6 +140,7 @@ fn render_spaces_list(snapshot: &BrowserSnapshot, cx: &mut Context<ElyShell>) ->
|
|||||||
fn render_space_row(
|
fn render_space_row(
|
||||||
index: usize,
|
index: usize,
|
||||||
space: &Space,
|
space: &Space,
|
||||||
|
snapshot: &BrowserSnapshot,
|
||||||
active: bool,
|
active: bool,
|
||||||
cx: &mut Context<ElyShell>,
|
cx: &mut Context<ElyShell>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
@@ -174,7 +175,7 @@ fn render_space_row(
|
|||||||
.text_xs()
|
.text_xs()
|
||||||
.truncate()
|
.truncate()
|
||||||
.text_color(rgb(colors::MUTED))
|
.text_color(rgb(colors::MUTED))
|
||||||
.child(space_detail_label(space)),
|
.child(space_detail_label(space, &snapshot.profiles)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -227,14 +228,24 @@ fn space_avatar(space: &Space) -> AnyElement {
|
|||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn space_detail_label(space: &Space) -> String {
|
fn space_detail_label(space: &Space, profiles: &[Profile]) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} - {}",
|
"{} - {} - {}",
|
||||||
accent_label(space.accent_hex()),
|
accent_label(space.accent_hex()),
|
||||||
archive_policy_label(space.archive_policy())
|
archive_policy_label(space.archive_policy()),
|
||||||
|
default_profile_label(space, profiles)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_profile_label(space: &Space, profiles: &[Profile]) -> String {
|
||||||
|
let Some(profile) = profiles.iter().find(|profile| profile.id() == space.default_profile_id())
|
||||||
|
else {
|
||||||
|
return "Default profile unavailable".to_string();
|
||||||
|
};
|
||||||
|
|
||||||
|
format!("Default profile: {}", profile.name())
|
||||||
|
}
|
||||||
|
|
||||||
fn accent_label(accent_hex: u32) -> String {
|
fn accent_label(accent_hex: u32) -> String {
|
||||||
format!("#{accent_hex:06X}")
|
format!("#{accent_hex:06X}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,13 +106,14 @@ pub struct BrowserCore {
|
|||||||
|
|
||||||
impl BrowserCore {
|
impl BrowserCore {
|
||||||
pub fn new(config: InitialBrowserConfig) -> Result<Self, CoreError> {
|
pub fn new(config: InitialBrowserConfig) -> Result<Self, CoreError> {
|
||||||
let space = Space::new(config.space_name, config.space_icon, 0xf54e00);
|
|
||||||
let profile = Profile::new(config.profile_name, 0x26251e, ProfileKind::Standard);
|
let profile = Profile::new(config.profile_name, 0x26251e, ProfileKind::Standard);
|
||||||
|
let active_profile_id = profile.id().clone();
|
||||||
|
let space =
|
||||||
|
Space::new(config.space_name, config.space_icon, 0xf54e00, active_profile_id.clone());
|
||||||
let new_tab_destination = config.new_tab_destination;
|
let new_tab_destination = config.new_tab_destination;
|
||||||
let new_tab_url = new_tab_destination.url()?;
|
let new_tab_url = new_tab_destination.url()?;
|
||||||
let new_tab_title = tab_title(&new_tab_url);
|
let new_tab_title = tab_title(&new_tab_url);
|
||||||
let active_space_id = space.id().clone();
|
let active_space_id = space.id().clone();
|
||||||
let active_profile_id = profile.id().clone();
|
|
||||||
let tab = BrowserTab::new(
|
let tab = BrowserTab::new(
|
||||||
TabId::new(),
|
TabId::new(),
|
||||||
active_space_id.clone(),
|
active_space_id.clone(),
|
||||||
@@ -162,13 +163,10 @@ impl BrowserCore {
|
|||||||
icon: impl Into<String>,
|
icon: impl Into<String>,
|
||||||
accent_hex: u32,
|
accent_hex: u32,
|
||||||
) -> Result<SpaceId, CoreError> {
|
) -> Result<SpaceId, CoreError> {
|
||||||
let space = Space::new(name, icon, accent_hex);
|
let space = Space::new(name, icon, accent_hex, self.active_profile_id.clone());
|
||||||
let space_id = space.id().clone();
|
let space_id = space.id().clone();
|
||||||
let tab = self.build_tab_for(
|
let default_profile_id = space.default_profile_id().clone();
|
||||||
space_id.clone(),
|
let tab = self.build_tab_for(space_id.clone(), default_profile_id, self.new_tab_url()?);
|
||||||
self.active_profile_id.clone(),
|
|
||||||
self.new_tab_url()?,
|
|
||||||
);
|
|
||||||
let tab_id = tab.id().clone();
|
let tab_id = tab.id().clone();
|
||||||
|
|
||||||
self.spaces.push(space);
|
self.spaces.push(space);
|
||||||
@@ -200,11 +198,14 @@ impl BrowserCore {
|
|||||||
return Ok(tab_id);
|
return Ok(tab_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tab = self.build_tab_for(
|
let default_profile_id = self
|
||||||
space_id.clone(),
|
.spaces
|
||||||
self.active_profile_id.clone(),
|
.iter()
|
||||||
self.new_tab_url()?,
|
.find(|space| space.id() == space_id)
|
||||||
);
|
.ok_or_else(|| CoreError::SpaceNotFound { id: space_id.clone() })?
|
||||||
|
.default_profile_id()
|
||||||
|
.clone();
|
||||||
|
let tab = self.build_tab_for(space_id.clone(), default_profile_id, self.new_tab_url()?);
|
||||||
let tab_id = tab.id().clone();
|
let tab_id = tab.id().clone();
|
||||||
self.tabs.push(tab);
|
self.tabs.push(tab);
|
||||||
self.select_tab(&tab_id)?;
|
self.select_tab(&tab_id)?;
|
||||||
@@ -233,6 +234,24 @@ impl BrowserCore {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_space_default_profile(
|
||||||
|
&mut self,
|
||||||
|
space_id: &SpaceId,
|
||||||
|
profile_id: &ProfileId,
|
||||||
|
) -> Result<(), CoreError> {
|
||||||
|
if !self.profiles.iter().any(|profile| profile.id() == profile_id) {
|
||||||
|
return Err(CoreError::ProfileNotFound { id: profile_id.clone() });
|
||||||
|
}
|
||||||
|
|
||||||
|
let space = self
|
||||||
|
.spaces
|
||||||
|
.iter_mut()
|
||||||
|
.find(|space| space.id() == space_id)
|
||||||
|
.ok_or_else(|| CoreError::SpaceNotFound { id: space_id.clone() })?;
|
||||||
|
space.set_default_profile_id(profile_id.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_search_engine(&mut self, search_engine: SearchEngine) {
|
pub fn set_search_engine(&mut self, search_engine: SearchEngine) {
|
||||||
self.search_engine = search_engine;
|
self.search_engine = search_engine;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use ely_browser_core::{BrowserCore, CoreError, InitialBrowserConfig};
|
||||||
|
use ely_domain::{ProfileId, ProfileKind};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn created_space_binds_current_profile_as_default() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
let research_profile_id = core.create_profile("Research", 0x9fc9a2, ProfileKind::Standard)?;
|
||||||
|
|
||||||
|
let research_space_id = core.create_space("Research", "R", 0x9fc9a2)?;
|
||||||
|
let snapshot = core.snapshot()?;
|
||||||
|
let Some(research_space) =
|
||||||
|
snapshot.spaces.iter().find(|space| space.id() == &research_space_id)
|
||||||
|
else {
|
||||||
|
return Err("missing research space".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(research_space.default_profile_id(), &research_profile_id);
|
||||||
|
assert_eq!(snapshot.active_profile_id, research_profile_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn space_default_profile_updates_with_profile_validation() -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut core = BrowserCore::new(InitialBrowserConfig::ely_defaults()?)?;
|
||||||
|
let work_space_id = core.snapshot()?.active_space_id;
|
||||||
|
let research_profile_id = core.create_profile("Research", 0x9fc9a2, ProfileKind::Standard)?;
|
||||||
|
|
||||||
|
core.set_space_default_profile(&work_space_id, &research_profile_id)?;
|
||||||
|
let snapshot = core.snapshot()?;
|
||||||
|
let Some(work_space) = snapshot.spaces.iter().find(|space| space.id() == &work_space_id) else {
|
||||||
|
return Err("missing work space".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(work_space.default_profile_id(), &research_profile_id);
|
||||||
|
|
||||||
|
let missing_profile_id = ProfileId::new();
|
||||||
|
let error = match core.set_space_default_profile(&work_space_id, &missing_profile_id) {
|
||||||
|
Err(error) => error,
|
||||||
|
Ok(_) => return Err("space default profile should require an existing profile".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(error, CoreError::ProfileNotFound { id: missing_profile_id });
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::SpaceId;
|
use crate::{ProfileId, SpaceId};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum ArchivePolicy {
|
pub enum ArchivePolicy {
|
||||||
@@ -12,17 +12,24 @@ pub struct Space {
|
|||||||
name: String,
|
name: String,
|
||||||
icon: String,
|
icon: String,
|
||||||
accent_hex: u32,
|
accent_hex: u32,
|
||||||
|
default_profile_id: ProfileId,
|
||||||
archive_policy: ArchivePolicy,
|
archive_policy: ArchivePolicy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Space {
|
impl Space {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: impl Into<String>, icon: impl Into<String>, accent_hex: u32) -> Self {
|
pub fn new(
|
||||||
|
name: impl Into<String>,
|
||||||
|
icon: impl Into<String>,
|
||||||
|
accent_hex: u32,
|
||||||
|
default_profile_id: ProfileId,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: SpaceId::new(),
|
id: SpaceId::new(),
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
icon: icon.into(),
|
icon: icon.into(),
|
||||||
accent_hex,
|
accent_hex,
|
||||||
|
default_profile_id,
|
||||||
archive_policy: ArchivePolicy::Manual,
|
archive_policy: ArchivePolicy::Manual,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,6 +54,15 @@ impl Space {
|
|||||||
self.accent_hex
|
self.accent_hex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn default_profile_id(&self) -> &ProfileId {
|
||||||
|
&self.default_profile_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_default_profile_id(&mut self, profile_id: ProfileId) {
|
||||||
|
self.default_profile_id = profile_id;
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn archive_policy(&self) -> &ArchivePolicy {
|
pub fn archive_policy(&self) -> &ArchivePolicy {
|
||||||
&self.archive_policy
|
&self.archive_policy
|
||||||
|
|||||||
Reference in New Issue
Block a user