Restore settings shell tab topology

This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 17:12:17 -04:00
1 parent 16b5bcb825
commit f0d37fe56e
4 files changed
+216 -131

No files matched your search

@@ -2,147 +2,219 @@ use super::*;
impl AppRoot {
pub(super) fn render_settings(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ {
let current = self.snapshot.current_company();
let execution_mode = current
.map(|item| item.execution_mode.clone())
.unwrap_or_else(|| "ai_ceo".to_string());
div()
.flex()
.flex_col()
.gap_6()
.child(
div()
.w(px(220.0))
.p_4()
.gap_2()
.rounded_lg()
.border_1()
.border_color(theme::panel_border())
.bg(theme::panel())
.child(settings_nav_row("General", true))
.child(settings_nav_row("Execution mode", false))
.child(settings_nav_row("Providers", false))
.child(settings_nav_row("Shortcuts", false))
.child(settings_nav_row("Data", false))
.child(settings_nav_row("Secrets", false)),
)
.child(
div()
.flex_1()
.gap_6()
.child(settings_panel(
"General",
vec![
settings_action_row(
"Theme",
self.snapshot.theme.clone(),
vec![
settings_action_button(
"System",
self.snapshot.theme == "system",
cx,
|this, cx| this.update_theme("system", cx),
)
.into_any_element(),
settings_action_button(
"Light",
self.snapshot.theme == "light",
cx,
|this, cx| this.update_theme("light", cx),
)
.into_any_element(),
settings_action_button(
"Dark",
self.snapshot.theme == "dark",
cx,
|this, cx| this.update_theme("dark", cx),
)
.into_any_element(),
],
),
settings_action_row(
"Locale",
self.snapshot.locale.clone(),
vec![
settings_action_button(
"EN",
self.snapshot.locale == "en",
cx,
|this, cx| this.update_locale("en", cx),
)
.into_any_element(),
settings_action_button(
"ZH",
self.snapshot.locale == "zh",
cx,
|this, cx| this.update_locale("zh", cx),
)
.into_any_element(),
],
),
settings_readonly_row(
"Profile path",
self.snapshot.profile_path.clone(),
),
],
))
.child(settings_panel(
"Execution mode",
vec![settings_action_row(
"Company mode",
execution_mode.clone(),
vec![
settings_action_button(
"AI CEO",
execution_mode == "ai_ceo",
cx,
|this, cx| this.update_execution_mode("ai_ceo", cx),
)
.into_any_element(),
settings_action_button(
"AI Co-Founder",
execution_mode == "ai_cofounder",
cx,
|this, cx| this.update_execution_mode("ai_cofounder", cx),
)
.into_any_element(),
],
)],
))
.child(settings_panel(
"Providers",
vec![settings_readonly_row(
"Configured connectors",
self.snapshot.connectors.len().to_string(),
)],
))
.child(settings_panel(
"Data",
vec![
settings_readonly_row("Stored profile", "Local SQLite".to_string()),
settings_readonly_row("Current company", current_company_name(current)),
],
)),
)
.child(settings_tabs(self.state.settings_tab, cx))
.child(self.render_active_settings_panel(cx))
}
fn render_active_settings_panel(&self, cx: &mut Context<Self>) -> gpui::AnyElement {
match self.state.settings_tab {
SettingsTab::General => self.render_general_settings_panel(cx).into_any_element(),
SettingsTab::Mode => self.render_mode_settings_panel(cx).into_any_element(),
SettingsTab::Providers => self.render_providers_settings_panel().into_any_element(),
SettingsTab::Shortcuts => self.render_shortcuts_settings_panel().into_any_element(),
SettingsTab::Data => self.render_data_settings_panel().into_any_element(),
SettingsTab::Secrets => self.render_secrets_settings_panel().into_any_element(),
}
}
fn render_general_settings_panel(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ {
settings_panel(
"General",
vec![
settings_action_row(
"Theme",
self.snapshot.theme.clone(),
vec![
settings_action_button(
"System",
self.snapshot.theme == "system",
cx,
|this, cx| this.update_theme("system", cx),
)
.into_any_element(),
settings_action_button(
"Light",
self.snapshot.theme == "light",
cx,
|this, cx| this.update_theme("light", cx),
)
.into_any_element(),
settings_action_button(
"Dark",
self.snapshot.theme == "dark",
cx,
|this, cx| this.update_theme("dark", cx),
)
.into_any_element(),
],
),
settings_action_row(
"Locale",
self.snapshot.locale.clone(),
vec![
settings_action_button(
"EN",
self.snapshot.locale == "en",
cx,
|this, cx| this.update_locale("en", cx),
)
.into_any_element(),
settings_action_button(
"ZH",
self.snapshot.locale == "zh",
cx,
|this, cx| this.update_locale("zh", cx),
)
.into_any_element(),
],
),
settings_readonly_row("Profile path", self.snapshot.profile_path.clone()),
],
)
}
fn render_mode_settings_panel(&self, cx: &mut Context<Self>) -> impl IntoElement + '_ {
let execution_mode = self
.snapshot
.current_company()
.map(|item| item.execution_mode.clone())
.unwrap_or_else(|| "ai_ceo".to_string());
settings_panel(
"Execution mode",
vec![settings_action_row(
"Company mode",
execution_mode.clone(),
vec![
settings_action_button("AI CEO", execution_mode == "ai_ceo", cx, |this, cx| {
this.update_execution_mode("ai_ceo", cx)
})
.into_any_element(),
settings_action_button(
"AI Co-Founder",
execution_mode == "ai_cofounder",
cx,
|this, cx| this.update_execution_mode("ai_cofounder", cx),
)
.into_any_element(),
],
)],
)
}
fn render_providers_settings_panel(&self) -> impl IntoElement + '_ {
settings_panel(
"Providers",
vec![
settings_readonly_row(
"Configured connectors",
self.snapshot.connectors.len().to_string(),
),
settings_readonly_row(
"Ready connectors",
self.snapshot
.connectors
.iter()
.filter(|item| item.status == "ready" || item.auth_state == "ready")
.count()
.to_string(),
),
],
)
}
fn render_shortcuts_settings_panel(&self) -> impl IntoElement + '_ {
settings_panel(
"Shortcuts",
vec![
settings_readonly_row("Open inbox", "g then i".to_string()),
settings_readonly_row("Open runs", "g then r".to_string()),
settings_readonly_row("Open settings", "g then s".to_string()),
],
)
}
fn render_data_settings_panel(&self) -> impl IntoElement + '_ {
settings_panel(
"Data",
vec![
settings_readonly_row("Stored profile", "Local SQLite".to_string()),
settings_readonly_row(
"Current company",
current_company_name(self.snapshot.current_company()),
),
settings_readonly_row("Documents", self.snapshot.documents.len().to_string()),
settings_readonly_row("Artifacts", self.snapshot.artifacts.len().to_string()),
],
)
}
fn render_secrets_settings_panel(&self) -> impl IntoElement + '_ {
settings_panel(
"Secrets",
vec![settings_readonly_row(
"Connector auth surfaces",
self.snapshot.connectors.len().to_string(),
)],
)
}
}
fn settings_nav_row(label: &'static str, active: bool) -> impl IntoElement {
fn settings_tabs(cx_tab: SettingsTab, cx: &mut Context<AppRoot>) -> impl IntoElement {
div()
.flex()
.gap_1()
.border_b_1()
.border_color(theme::panel_border())
.children([
settings_tab_button("General", SettingsTab::General, cx_tab, cx).into_any_element(),
settings_tab_button("Mode", SettingsTab::Mode, cx_tab, cx).into_any_element(),
settings_tab_button("Providers", SettingsTab::Providers, cx_tab, cx).into_any_element(),
settings_tab_button("Shortcuts", SettingsTab::Shortcuts, cx_tab, cx).into_any_element(),
settings_tab_button("Data", SettingsTab::Data, cx_tab, cx).into_any_element(),
settings_tab_button("Secrets", SettingsTab::Secrets, cx_tab, cx).into_any_element(),
])
}
fn settings_tab_button(
label: &'static str,
tab: SettingsTab,
active_tab: SettingsTab,
cx: &mut Context<AppRoot>,
) -> impl IntoElement {
let active = tab == active_tab;
div()
.id(SharedString::from(format!("settings-tab-{label}")))
.relative()
.px_4()
.py_3()
.rounded_lg()
.bg(if active {
theme::selection_fill()
} else {
theme::panel()
})
.py_2()
.cursor_pointer()
.text_sm()
.text_color(if active {
theme::sidebar_text_active()
theme::text_primary()
} else {
theme::text_secondary()
theme::text_muted()
})
.hover(|style| style.text_color(theme::text_primary()))
.on_click(cx.listener(move |this, _, _, cx| {
this.state.settings_tab = tab;
cx.notify();
}))
.child(label)
.when(active, |element| {
element.child(
div()
.absolute()
.left(px(8.0))
.right(px(8.0))
.bottom(px(-1.0))
.h(px(2.0))
.bg(theme::primary_action()),
)
})
}
fn settings_panel(label: &'static str, rows: Vec<gpui::AnyElement>) -> impl IntoElement {