agent_ui: Add some more design tweaks to the sandbox tooltip (#60085)

Quick follow up to https://github.com/zed-industries/zed/pull/59980 with
some adjustments.

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2026-06-29 11:27:44 -03:00 committed by GitHub
parent 26ee53e5aa
commit c070f7c8ce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 47 additions and 29 deletions

View file

@ -4646,7 +4646,11 @@ impl ThreadView {
// settings scope (greyed) for context above the disabled status.
(ThreadSandbox::Sandboxed(settings_policy), ThreadSandbox::Unsandboxed) => {
let settings = augment_settings_sandbox_policy(settings_policy, baseline);
SandboxStatusTooltip::disabled_for_thread(sandbox_section(&settings, true))
SandboxStatusTooltip::disabled_for_thread(sandbox_section(
"Defined in your settings:",
&settings,
true,
))
}
(
ThreadSandbox::Sandboxed(settings_policy),
@ -4655,8 +4659,11 @@ impl ThreadView {
let settings = augment_settings_sandbox_policy(settings_policy, baseline);
// Omit the per-thread section when it grants nothing extra.
let thread = (!sandbox_policy_grants_nothing(&thread_policy))
.then(|| sandbox_section(&thread_policy, false));
SandboxStatusTooltip::enabled(sandbox_section(&settings, true), thread)
.then(|| sandbox_section("Allowed for this thread:", &thread_policy, false));
SandboxStatusTooltip::enabled(
sandbox_section("Defined in your settings:", &settings, true),
thread,
)
}
};
@ -5625,25 +5632,28 @@ fn augment_settings_sandbox_policy(
policy
}
fn sandbox_section(policy: &SandboxPolicy, show_empty: bool) -> SandboxSection {
fn sandbox_section(title: &str, policy: &SandboxPolicy, show_empty: bool) -> SandboxSection {
let write_empty = fs_grants_nothing(&policy.fs);
let network_empty = network_grants_nothing(&policy.network);
// Git access is only surfaced when granted, so it never shows a "None" row.
let git_empty = git_grants_nothing(&policy.git);
let mut section = SandboxSection::new();
let mut section = SandboxSection::new(title.to_string());
if show_empty || !write_empty {
section =
section.group(SandboxGroup::new("Write Access").rows(sandbox_fs_rows(&policy.fs)));
}
if show_empty || !network_empty {
section = section
.group(SandboxGroup::new("Network Access").rows(sandbox_network_rows(&policy.network)));
}
if !git_empty {
section = section
.group(SandboxGroup::new("Git Metadata Access").rows(sandbox_git_rows(&policy.git)));
}
section
}

View file

@ -58,21 +58,21 @@ impl SandboxRow {
};
h_flex()
.items_start()
.min_w_0()
.w_full()
.gap_1()
.gap_1p5()
.child(icon)
.child(
Label::new(label)
.size(LabelSize::XSmall)
.buffer_font(cx)
.truncate_start(),
div()
.flex_1()
.min_w_0()
.overflow_hidden()
.child(Label::new(label).size(LabelSize::XSmall).buffer_font(cx)),
)
.into_any_element()
}
}
/// A labelled group of rows (e.g. "Write Access", "Network Access").
#[derive(Clone)]
pub struct SandboxGroup {
heading: SharedString,
@ -99,7 +99,7 @@ impl SandboxGroup {
fn render(self, cx: &App) -> impl IntoElement {
v_flex()
.gap_1()
.gap_1p5()
.child(
Label::new(self.heading)
.size(LabelSize::Small)
@ -109,14 +109,18 @@ impl SandboxGroup {
}
}
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct SandboxSection {
title: SharedString,
groups: Vec<SandboxGroup>,
}
impl SandboxSection {
pub fn new() -> Self {
Self::default()
pub fn new(title: impl Into<SharedString>) -> Self {
Self {
title: title.into(),
groups: Vec::new(),
}
}
pub fn group(mut self, group: SandboxGroup) -> Self {
@ -125,14 +129,16 @@ impl SandboxSection {
}
fn render(self, cx: &App) -> AnyElement {
let mut section = v_flex().gap_1();
for (index, group) in self.groups.into_iter().enumerate() {
if index > 0 {
section = section.child(Divider::horizontal());
}
section = section.child(group.render(cx));
}
section.into_any_element()
v_flex()
.gap_2()
.child(Label::new(self.title).size(LabelSize::Small))
.children(self.groups.into_iter().map(|group| {
v_flex()
.gap_2()
.child(Divider::horizontal())
.child(group.render(cx))
}))
.into_any_element()
}
}
@ -179,9 +185,11 @@ impl RenderOnce for SandboxStatusTooltip {
.child(Label::new("Sandboxing is disabled for this thread").size(LabelSize::Small))
.into_any_element(),
SandboxStatusTooltip::Enabled { settings, thread } => v_flex()
.gap_2()
.child(settings.render(cx))
.children(thread.map(|thread| {
v_flex()
.gap_2()
.child(Divider::horizontal())
.child(thread.render(cx))
}))
@ -189,7 +197,7 @@ impl RenderOnce for SandboxStatusTooltip {
};
v_flex()
.min_w(rems(15.))
.w(rems_from_px(280.))
.gap_1()
.child(Label::new("Sandboxing"))
.child(content)
@ -212,7 +220,7 @@ impl Component for SandboxStatusTooltip {
}
fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
let settings_section = SandboxSection::new()
let settings_section = SandboxSection::new("Defined in your settings:")
.group(SandboxGroup::new("Write Access").rows([
SandboxRow::path("/Users/you/project"),
SandboxRow::path("/tmp (isolated)"),
@ -222,7 +230,7 @@ impl Component for SandboxStatusTooltip {
SandboxRow::domain("*.npmjs.org"),
]));
let thread_section = SandboxSection::new()
let thread_section = SandboxSection::new("Allowed for this thread:")
.group(
SandboxGroup::new("Write Access").row(SandboxRow::path("/Users/you/project/build")),
)
@ -232,7 +240,7 @@ impl Component for SandboxStatusTooltip {
.row(SandboxRow::git("/Users/you/project/.git")),
);
let unrestricted_section = SandboxSection::new()
let unrestricted_section = SandboxSection::new("Defined in your settings:")
.group(
SandboxGroup::new("Write Access")
.row(SandboxRow::message("All paths (unrestricted)")),