agent: Polish single-file review toolbar controls (#29866)
This commit is contained in:
parent
545ae27079
commit
2e3baef299
6 changed files with 56 additions and 60 deletions
1
assets/icons/list_collapse.svg
Normal file
1
assets/icons/list_collapse.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-list-collapse-icon lucide-list-collapse"><path d="m3 10 2.5-2.5L3 5"/><path d="m3 19 2.5-2.5L3 14"/><path d="M10 6h11"/><path d="M10 12h11"/><path d="M10 18h11"/></svg>
|
After Width: | Height: | Size: 371 B |
|
@ -26,7 +26,7 @@ use std::{
|
||||||
ops::Range,
|
ops::Range,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use ui::{IconButtonShape, KeyBinding, Tooltip, prelude::*, vertical_divider};
|
use ui::{Divider, IconButtonShape, KeyBinding, Tooltip, prelude::*, vertical_divider};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
Item, ItemHandle, ItemNavHistory, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView,
|
Item, ItemHandle, ItemNavHistory, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView,
|
||||||
|
@ -937,7 +937,7 @@ impl AgentDiffToolbar {
|
||||||
Some(AgentDiffToolbarItem::Pane(_)) => ToolbarItemLocation::PrimaryRight,
|
Some(AgentDiffToolbarItem::Pane(_)) => ToolbarItemLocation::PrimaryRight,
|
||||||
Some(AgentDiffToolbarItem::Editor { state, .. }) => match state {
|
Some(AgentDiffToolbarItem::Editor { state, .. }) => match state {
|
||||||
EditorState::Generating | EditorState::Reviewing => {
|
EditorState::Generating | EditorState::Reviewing => {
|
||||||
ToolbarItemLocation::PrimaryLeft
|
ToolbarItemLocation::PrimaryRight
|
||||||
}
|
}
|
||||||
EditorState::Idle => ToolbarItemLocation::Hidden,
|
EditorState::Idle => ToolbarItemLocation::Hidden,
|
||||||
},
|
},
|
||||||
|
@ -990,6 +990,11 @@ impl ToolbarItemView for AgentDiffToolbar {
|
||||||
|
|
||||||
impl Render for AgentDiffToolbar {
|
impl Render for AgentDiffToolbar {
|
||||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let generating_label = div()
|
||||||
|
.w(rems_from_px(110.)) // Arbitrary size so the label doesn't dance around
|
||||||
|
.child(AnimatedLabel::new("Generating"))
|
||||||
|
.into_any();
|
||||||
|
|
||||||
let Some(active_item) = self.active_item.as_ref() else {
|
let Some(active_item) = self.active_item.as_ref() else {
|
||||||
return Empty.into_any();
|
return Empty.into_any();
|
||||||
};
|
};
|
||||||
|
@ -1004,24 +1009,13 @@ impl Render for AgentDiffToolbar {
|
||||||
|
|
||||||
let content = match state {
|
let content = match state {
|
||||||
EditorState::Idle => return Empty.into_any(),
|
EditorState::Idle => return Empty.into_any(),
|
||||||
EditorState::Generating => vec![
|
EditorState::Generating => vec![generating_label],
|
||||||
h_flex()
|
|
||||||
.ml_1()
|
|
||||||
.gap_1p5()
|
|
||||||
.w_32()
|
|
||||||
.child(Icon::new(IconName::ZedAssistant))
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.w(rems(6.5625))
|
|
||||||
.child(AnimatedLabel::new("Generating")),
|
|
||||||
)
|
|
||||||
.into_any(),
|
|
||||||
],
|
|
||||||
EditorState::Reviewing => vec![
|
EditorState::Reviewing => vec![
|
||||||
h_flex()
|
h_flex()
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("hunk-up", IconName::ArrowUp)
|
IconButton::new("hunk-up", IconName::ArrowUp)
|
||||||
.tooltip(ui::Tooltip::for_action_title_in(
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(Tooltip::for_action_title_in(
|
||||||
"Previous Hunk",
|
"Previous Hunk",
|
||||||
&GoToPreviousHunk,
|
&GoToPreviousHunk,
|
||||||
&editor_focus_handle,
|
&editor_focus_handle,
|
||||||
|
@ -1039,7 +1033,8 @@ impl Render for AgentDiffToolbar {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
IconButton::new("hunk-down", IconName::ArrowDown)
|
IconButton::new("hunk-down", IconName::ArrowDown)
|
||||||
.tooltip(ui::Tooltip::for_action_title_in(
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(Tooltip::for_action_title_in(
|
||||||
"Next Hunk",
|
"Next Hunk",
|
||||||
&GoToHunk,
|
&GoToHunk,
|
||||||
&editor_focus_handle,
|
&editor_focus_handle,
|
||||||
|
@ -1053,8 +1048,9 @@ impl Render for AgentDiffToolbar {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.into_any(),
|
.into_any(),
|
||||||
vertical_divider().into_any_element(),
|
Divider::vertical().into_any_element(),
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.gap_0p5()
|
||||||
.child(
|
.child(
|
||||||
Button::new("reject-all", "Reject All")
|
Button::new("reject-all", "Reject All")
|
||||||
.key_binding({
|
.key_binding({
|
||||||
|
@ -1086,30 +1082,24 @@ impl Render for AgentDiffToolbar {
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.into_any(),
|
.into_any(),
|
||||||
|
Divider::vertical().into_any_element(),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.bg(cx.theme().colors().surface_background)
|
.track_focus(&editor_focus_handle)
|
||||||
.rounded_md()
|
.size_full()
|
||||||
.p_1()
|
.child(
|
||||||
.mx_2()
|
h_flex()
|
||||||
|
.py(DynamicSpacing::Base08.rems(cx))
|
||||||
|
.px_2()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.children(content)
|
.children(content)
|
||||||
.child(vertical_divider())
|
|
||||||
.track_focus(&editor_focus_handle)
|
|
||||||
.on_action({
|
|
||||||
let editor = editor.clone();
|
|
||||||
move |_action: &OpenAgentDiff, window, cx| {
|
|
||||||
AgentDiff::global(cx).update(cx, |agent_diff, cx| {
|
|
||||||
agent_diff.deploy_pane_from_editor(&editor, window, cx);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.when_some(editor.read(cx).workspace(), |this, _workspace| {
|
.when_some(editor.read(cx).workspace(), |this, _workspace| {
|
||||||
this.child(
|
this.child(
|
||||||
IconButton::new("review", IconName::ListTree)
|
IconButton::new("review", IconName::ListCollapse)
|
||||||
.tooltip(ui::Tooltip::for_action_title_in(
|
.icon_size(IconSize::Small)
|
||||||
|
.tooltip(Tooltip::for_action_title_in(
|
||||||
"Review All Files",
|
"Review All Files",
|
||||||
&OpenAgentDiff,
|
&OpenAgentDiff,
|
||||||
&editor_focus_handle,
|
&editor_focus_handle,
|
||||||
|
@ -1120,6 +1110,16 @@ impl Render for AgentDiffToolbar {
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.child(vertical_divider())
|
||||||
|
.on_action({
|
||||||
|
let editor = editor.clone();
|
||||||
|
move |_action: &OpenAgentDiff, window, cx| {
|
||||||
|
AgentDiff::global(cx).update(cx, |agent_diff, cx| {
|
||||||
|
agent_diff.deploy_pane_from_editor(&editor, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
@ -1130,10 +1130,7 @@ impl Render for AgentDiffToolbar {
|
||||||
|
|
||||||
let is_generating = agent_diff.read(cx).thread.read(cx).is_generating();
|
let is_generating = agent_diff.read(cx).thread.read(cx).is_generating();
|
||||||
if is_generating {
|
if is_generating {
|
||||||
return div()
|
return div().px_2().child(generating_label).into_any();
|
||||||
.w(rems(6.5625)) // Arbitrary 105px size—so the label doesn't dance around
|
|
||||||
.child(AnimatedLabel::new("Generating"))
|
|
||||||
.into_any();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_empty = agent_diff.read(cx).multibuffer.read(cx).is_empty();
|
let is_empty = agent_diff.read(cx).multibuffer.read(cx).is_empty();
|
||||||
|
@ -1144,11 +1141,9 @@ impl Render for AgentDiffToolbar {
|
||||||
let focus_handle = agent_diff.focus_handle(cx);
|
let focus_handle = agent_diff.focus_handle(cx);
|
||||||
|
|
||||||
h_group_xl()
|
h_group_xl()
|
||||||
.my_neg_1()
|
.px_2()
|
||||||
.items_center()
|
.items_center()
|
||||||
.p_1()
|
|
||||||
.flex_wrap()
|
.flex_wrap()
|
||||||
.justify_between()
|
|
||||||
.child(
|
.child(
|
||||||
h_group_sm()
|
h_group_sm()
|
||||||
.child(
|
.child(
|
||||||
|
@ -2086,7 +2081,7 @@ mod tests {
|
||||||
// The toolbar is displayed in the right state
|
// The toolbar is displayed in the right state
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
diff_toolbar.read_with(cx, |toolbar, cx| toolbar.location(cx)),
|
diff_toolbar.read_with(cx, |toolbar, cx| toolbar.location(cx)),
|
||||||
ToolbarItemLocation::PrimaryLeft
|
ToolbarItemLocation::PrimaryRight
|
||||||
);
|
);
|
||||||
assert!(diff_toolbar.read_with(cx, |toolbar, _cx| matches!(
|
assert!(diff_toolbar.read_with(cx, |toolbar, _cx| matches!(
|
||||||
toolbar.active_item,
|
toolbar.active_item,
|
||||||
|
@ -2105,7 +2100,7 @@ mod tests {
|
||||||
override_toolbar_agent_review_setting(true, cx);
|
override_toolbar_agent_review_setting(true, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
diff_toolbar.read_with(cx, |toolbar, cx| toolbar.location(cx)),
|
diff_toolbar.read_with(cx, |toolbar, cx| toolbar.location(cx)),
|
||||||
ToolbarItemLocation::PrimaryLeft
|
ToolbarItemLocation::PrimaryRight
|
||||||
);
|
);
|
||||||
|
|
||||||
// After keeping a hunk, the cursor should be positioned on the second hunk.
|
// After keeping a hunk, the cursor should be positioned on the second hunk.
|
||||||
|
|
|
@ -895,8 +895,7 @@ impl Render for ProjectDiffToolbar {
|
||||||
.my_neg_1()
|
.my_neg_1()
|
||||||
.items_center()
|
.items_center()
|
||||||
.py_1()
|
.py_1()
|
||||||
.pl_2()
|
.px_2()
|
||||||
.pr_1()
|
|
||||||
.flex_wrap()
|
.flex_wrap()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.child(
|
.child(
|
||||||
|
|
|
@ -151,6 +151,7 @@ pub enum IconName {
|
||||||
LightBulb,
|
LightBulb,
|
||||||
LineHeight,
|
LineHeight,
|
||||||
Link,
|
Link,
|
||||||
|
ListCollapse,
|
||||||
ListTree,
|
ListTree,
|
||||||
ListX,
|
ListX,
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
|
|
|
@ -105,23 +105,23 @@ impl Render for Toolbar {
|
||||||
|
|
||||||
v_flex()
|
v_flex()
|
||||||
.group("toolbar")
|
.group("toolbar")
|
||||||
.p(DynamicSpacing::Base08.rems(cx))
|
.relative()
|
||||||
.when(has_left_items || has_right_items, |this| {
|
.when(has_left_items || has_right_items, |this| {
|
||||||
this.gap(DynamicSpacing::Base08.rems(cx))
|
this.gap(DynamicSpacing::Base08.rems(cx))
|
||||||
})
|
})
|
||||||
.border_b_1()
|
.border_b_1()
|
||||||
.border_color(cx.theme().colors().border_variant)
|
.border_color(cx.theme().colors().border_variant)
|
||||||
.relative()
|
|
||||||
.bg(cx.theme().colors().toolbar_background)
|
.bg(cx.theme().colors().toolbar_background)
|
||||||
.when(has_left_items || has_right_items, |this| {
|
.when(has_left_items || has_right_items, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.min_h(rems_from_px(24.))
|
.min_h_6()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.gap(DynamicSpacing::Base08.rems(cx))
|
.gap(DynamicSpacing::Base08.rems(cx))
|
||||||
.when(has_left_items, |this| {
|
.when(has_left_items, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.p(DynamicSpacing::Base08.rems(cx))
|
||||||
.flex_auto()
|
.flex_auto()
|
||||||
.justify_start()
|
.justify_start()
|
||||||
.overflow_x_hidden()
|
.overflow_x_hidden()
|
||||||
|
@ -131,6 +131,8 @@ impl Render for Toolbar {
|
||||||
.when(has_right_items, |this| {
|
.when(has_right_items, |this| {
|
||||||
this.child(
|
this.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
|
.h_full()
|
||||||
|
.flex_row_reverse()
|
||||||
.map(|el| {
|
.map(|el| {
|
||||||
if has_left_items {
|
if has_left_items {
|
||||||
// We're using `flex_none` here to prevent some flickering that can occur when the
|
// We're using `flex_none` here to prevent some flickering that can occur when the
|
||||||
|
|
|
@ -15,8 +15,8 @@ use gpui::{
|
||||||
use search::{BufferSearchBar, buffer_search};
|
use search::{BufferSearchBar, buffer_search};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use ui::{
|
use ui::{
|
||||||
ButtonStyle, ContextMenu, ContextMenuEntry, IconButton, IconButtonShape, IconName, IconSize,
|
ButtonStyle, ContextMenu, ContextMenuEntry, IconButton, IconName, IconSize, PopoverMenu,
|
||||||
PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*,
|
PopoverMenuHandle, Tooltip, prelude::*,
|
||||||
};
|
};
|
||||||
use vim_mode_setting::VimModeSetting;
|
use vim_mode_setting::VimModeSetting;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
|
@ -141,7 +141,6 @@ impl Render for QuickActionBar {
|
||||||
PopoverMenu::new("editor-selections-dropdown")
|
PopoverMenu::new("editor-selections-dropdown")
|
||||||
.trigger_with_tooltip(
|
.trigger_with_tooltip(
|
||||||
IconButton::new("toggle_editor_selections_icon", IconName::CursorIBeam)
|
IconButton::new("toggle_editor_selections_icon", IconName::CursorIBeam)
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.icon_size(IconSize::Small)
|
.icon_size(IconSize::Small)
|
||||||
.style(ButtonStyle::Subtle)
|
.style(ButtonStyle::Subtle)
|
||||||
.toggle_state(self.toggle_selections_handle.is_deployed()),
|
.toggle_state(self.toggle_selections_handle.is_deployed()),
|
||||||
|
@ -190,7 +189,6 @@ impl Render for QuickActionBar {
|
||||||
PopoverMenu::new("editor-settings")
|
PopoverMenu::new("editor-settings")
|
||||||
.trigger_with_tooltip(
|
.trigger_with_tooltip(
|
||||||
IconButton::new("toggle_editor_settings_icon", IconName::Sliders)
|
IconButton::new("toggle_editor_settings_icon", IconName::Sliders)
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.icon_size(IconSize::Small)
|
.icon_size(IconSize::Small)
|
||||||
.style(ButtonStyle::Subtle)
|
.style(ButtonStyle::Subtle)
|
||||||
.toggle_state(self.toggle_settings_handle.is_deployed()),
|
.toggle_state(self.toggle_settings_handle.is_deployed()),
|
||||||
|
@ -435,7 +433,8 @@ impl Render for QuickActionBar {
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("quick action bar")
|
.id("quick action bar")
|
||||||
.gap(DynamicSpacing::Base04.rems(cx))
|
.p(DynamicSpacing::Base08.rems(cx))
|
||||||
|
.gap(DynamicSpacing::Base01.rems(cx))
|
||||||
.children(self.render_repl_menu(cx))
|
.children(self.render_repl_menu(cx))
|
||||||
.children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
|
.children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
|
||||||
.children(search_button)
|
.children(search_button)
|
||||||
|
@ -490,7 +489,6 @@ impl RenderOnce for QuickActionBarButton {
|
||||||
let action = self.action.boxed_clone();
|
let action = self.action.boxed_clone();
|
||||||
|
|
||||||
IconButton::new(self.id.clone(), self.icon)
|
IconButton::new(self.id.clone(), self.icon)
|
||||||
.shape(IconButtonShape::Square)
|
|
||||||
.icon_size(IconSize::Small)
|
.icon_size(IconSize::Small)
|
||||||
.style(ButtonStyle::Subtle)
|
.style(ButtonStyle::Subtle)
|
||||||
.toggle_state(self.toggled)
|
.toggle_state(self.toggled)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue