This commit is contained in:
2026-08-05 01:08:26 -05:00
parent c321e17708
commit 2015498831
4 changed files with 110 additions and 96 deletions
+53 -68
View File
@@ -22,7 +22,7 @@ use galaxy_core::ui::theme::color::internal_colors;
use galaxy_util::local_or_remote_path::LocalOrRemotePath;
use galaxyui::elements::new_scrollable::SingleAxisConfig;
use galaxyui::elements::{
Align, Border, ChildAnchor, ChildView, ConstrainedBox, Container, CornerRadius,
Align, Border, ChildAnchor, ChildView, Clipped, ConstrainedBox, Container, CornerRadius,
CrossAxisAlignment, Empty, Expanded, Fill, Flex, FormattedTextElement, Hoverable,
MainAxisAlignment, MainAxisSize, NewScrollable, OffsetPositioning, ParentAnchor, ParentElement,
ParentOffsetBounds, Radius, Shrinkable, Stack, Text, Wrap,
@@ -85,18 +85,22 @@ use crate::ai::blocklist::inline_action::ask_user_question_view::AskUserQuestion
use crate::ai::blocklist::inline_action::aws_bedrock_credentials_error::AwsBedrockCredentialsErrorView;
use crate::ai::blocklist::inline_action::create_or_edit_document::CreateOrEditDocumentAction;
use crate::ai::blocklist::inline_action::inline_action_header::{
HeaderConfig, InteractionMode, INLINE_ACTION_HEADER_VERTICAL_PADDING,
ExpandedConfig, HeaderConfig, InteractionMode, INLINE_ACTION_HEADER_VERTICAL_PADDING,
INLINE_ACTION_HORIZONTAL_PADDING,
};
use crate::ai::blocklist::inline_action::inline_action_icons::{self, icon_size};
use crate::ai::blocklist::inline_action::requested_action::{
render_requested_action_body_text, render_requested_action_row_for_text, RenderableAction,
};
use crate::ai::blocklist::inline_action::requested_command::RequestedCommand;
use crate::ai::blocklist::inline_action::requested_command::{
format_command_text, RequestedCommand, REQUESTED_COMMAND_BODY_VERTICAL_PADDING,
VIEWING_COMMAND_DETAIL_MESSAGE,
};
use crate::ai::blocklist::inline_action::run_agents_card_view::RunAgentsCardView;
use crate::ai::blocklist::inline_action::search_codebase::SearchCodebaseView;
use crate::ai::blocklist::inline_action::suggested_unit_tests::SuggestedUnitTestsView;
use crate::ai::blocklist::inline_action::summarization::SummarizationView;
use crate::ai::blocklist::inline_action::tool_pane::render_tool_pane_shell;
use crate::ai::blocklist::inline_action::web_fetch::WebFetchView;
use crate::ai::blocklist::inline_action::web_search::WebSearchView;
use crate::ai::blocklist::keyboard_navigable_buttons::KeyboardNavigableButtons;
@@ -1287,7 +1291,6 @@ fn render_runtime_activity(
let state = props.collapsible_block_states.get(&output_message.id)?;
let appearance = Appearance::as_ref(app);
let theme = appearance.theme();
let text_color = blended_colors::text_main(theme, theme.background());
let output = activity
.output
.as_deref()
@@ -1296,56 +1299,51 @@ fn render_runtime_activity(
state.expansion_state,
CollapsibleExpansionState::Expanded { .. }
);
let mut content = Flex::column().with_cross_axis_alignment(CrossAxisAlignment::Stretch);
let title = Text::new(
activity.title.clone(),
appearance.monospace_font_family(),
appearance.monospace_font_size(),
)
.with_color(text_color)
.with_selectable(false)
.finish();
if output.is_some() {
let chevron = if is_expanded {
Icon::ChevronDown
} else {
Icon::ChevronRight
let icon = match activity.status.as_ref() {
Some(RuntimeActivityStatus::Pending) => icons::pending_icon(appearance),
Some(RuntimeActivityStatus::InProgress) => icons::yellow_running_icon(appearance),
Some(RuntimeActivityStatus::Completed) => inline_action_icons::green_check_icon(appearance),
Some(RuntimeActivityStatus::Failed) => inline_action_icons::red_x_icon(appearance),
Some(RuntimeActivityStatus::Other(_)) | None => icons::gray_circle_icon(appearance),
};
let icon_sz = icon_size(app);
let title = if is_expanded {
VIEWING_COMMAND_DETAIL_MESSAGE.to_owned()
} else {
format_command_text(&activity.title)
};
let mut header = HeaderConfig::new(title, app)
.with_selectable_text()
.with_icon(icon)
.with_corner_radius_override(if is_expanded && output.is_some() {
CornerRadius::with_top(Radius::Pixels(8.))
} else {
CornerRadius::with_all(Radius::Pixels(8.))
});
if !is_expanded {
header = header.with_font_family(appearance.monospace_font_family());
}
if output.is_some() {
let message_id = output_message.id.clone();
let mouse_state = state.expansion_toggle_mouse_state.clone();
let header = Hoverable::new(mouse_state, move |_| {
Flex::row()
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_child(Shrinkable::new(1., title).finish())
.with_child(
Container::new(
ConstrainedBox::new(chevron.to_galaxyui_icon(text_color.into()).finish())
.with_width(icon_sz)
.with_height(icon_sz)
.finish(),
)
.with_margin_left(6.)
.finish(),
)
.finish()
})
.with_cursor(Cursor::PointingHand)
.on_click(move |ctx, _, _| {
let command = activity.title.clone();
let expansion =
ExpandedConfig::new(is_expanded, state.expansion_toggle_mouse_state.clone())
.with_toggle_callback(move |ctx| {
ctx.dispatch_typed_action(AIBlockAction::ToggleCollapsibleBlockExpanded(
message_id.clone(),
));
})
.with_right_click_callback(move |ctx| {
ctx.dispatch_typed_action(AIBlockAction::StoreRightClickedCommand {
command: command.clone(),
});
content.add_child(
Flex::row()
.with_child(Shrinkable::new(1., header.finish()).finish())
.finish(),
);
} else {
content.add_child(title);
});
header = header.with_interaction_mode(InteractionMode::ManuallyExpandable(expansion));
}
let mut content = Flex::column()
.with_cross_axis_alignment(CrossAxisAlignment::Stretch)
.with_child(Clipped::new(header.render(app)).finish());
if let Some(output) = output {
let body = render_requested_action_body_text(
output.into(),
@@ -1364,31 +1362,18 @@ fn render_runtime_activity(
is_streaming,
320.,
) {
content.add_child(Container::new(scrollable).with_margin_top(12.).finish());
content.add_child(
Container::new(scrollable)
.with_horizontal_padding(INLINE_ACTION_HORIZONTAL_PADDING)
.with_vertical_padding(REQUESTED_COMMAND_BODY_VERTICAL_PADDING)
.with_background(theme.background())
.with_corner_radius(CornerRadius::with_bottom(Radius::Pixels(8.)))
.finish(),
);
}
}
let icon = match activity.status.as_ref() {
Some(RuntimeActivityStatus::Completed) => {
inline_action_icons::green_check_icon(appearance).finish()
}
Some(RuntimeActivityStatus::Failed) => inline_action_icons::red_x_icon(appearance).finish(),
Some(RuntimeActivityStatus::Pending)
| Some(RuntimeActivityStatus::InProgress)
| Some(RuntimeActivityStatus::Other(_))
| None => galaxyui::elements::Icon::new(
Icon::ClockRefresh.into(),
internal_colors::neutral_5(appearance.theme()),
)
.finish(),
};
Some(
RenderableAction::new_with_element(content.finish(), app)
.with_icon(icon)
.render(app)
.finish(),
)
Some(render_tool_pane_shell(content.finish(), false, false, app))
}
fn should_render_stopped_output(props: Props, app: &AppContext) -> bool {
@@ -16,5 +16,6 @@ pub(super) mod search_codebase;
pub(crate) mod search_results_common;
pub(crate) mod suggested_unit_tests;
pub(super) mod summarization;
pub(crate) mod tool_pane;
pub(super) mod web_fetch;
pub(super) mod web_search;
@@ -36,13 +36,13 @@ use crate::ai::blocklist::block::cli_controller::{
use crate::ai::blocklist::block::view_impl::output::action_icon;
use crate::ai::blocklist::block::view_impl::{
render_autonomy_checkbox_setting_speedbump_footer, render_citation, render_citation_chips,
CONTENT_HORIZONTAL_PADDING, CONTENT_ITEM_VERTICAL_MARGIN,
};
use crate::ai::blocklist::block::{AIBlockAction, AutonomySettingSpeedbump};
use crate::ai::blocklist::inline_action::inline_action_header::{
ExpandedConfig, HeaderConfig, InteractionMode, RightClickConfig,
INLINE_ACTION_HORIZONTAL_PADDING,
};
use crate::ai::blocklist::inline_action::tool_pane::render_tool_pane_shell;
use crate::ai::blocklist::model::{AIBlockModel, AIBlockModelHelper};
use crate::ai::blocklist::{
AIBlock, BlocklistAIActionEvent, BlocklistAIActionModel, BlocklistAIHistoryModel,
@@ -1600,14 +1600,9 @@ impl View for RequestedCommandView {
content.add_child(Clipped::new(footer).finish());
}
let border_color = if action_status
let has_highlighted_border = action_status
.as_ref()
.is_some_and(|status| status.is_blocked())
{
theme.accent()
} else {
theme.surface_2()
};
.is_some_and(|status| status.is_blocked());
// If the requested command is expanded above a terminal block or
// the next exchange flows directly after, remove bottom margin for
@@ -1637,21 +1632,12 @@ impl View for RequestedCommandView {
}))
&& !is_input_pinned_to_top);
let container = Container::new(content.finish())
.with_margin_left(if action_status.is_some_and(|status| status.is_blocked()) {
CONTENT_HORIZONTAL_PADDING
} else {
CONTENT_HORIZONTAL_PADDING + icon_size(app) + 16.
})
.with_margin_right(CONTENT_HORIZONTAL_PADDING)
.with_margin_bottom(if should_remove_bottom_margin {
0.
} else {
CONTENT_ITEM_VERTICAL_MARGIN
})
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
.with_border(Border::all(1.).with_border_fill(border_color))
.finish();
let container = render_tool_pane_shell(
content.finish(),
has_highlighted_border,
should_remove_bottom_margin,
app,
);
let mut root_stack = Stack::new();
root_stack.add_child(container);
@@ -0,0 +1,42 @@
use galaxy_core::ui::appearance::Appearance;
use warpui::elements::{Border, Container, CornerRadius, ParentElement, Radius};
use warpui::{AppContext, Element, SingletonEntity};
use super::inline_action_icons::icon_size;
use crate::ai::blocklist::block::view_impl::{
CONTENT_HORIZONTAL_PADDING, CONTENT_ITEM_VERTICAL_MARGIN,
};
/// Renders the shared outer shell used by native and runtime-owned tool panes.
///
/// Callers own execution and body content. This function owns the pane geometry
/// and theme treatment so display-only runtimes cannot drift from native tools.
pub(crate) fn render_tool_pane_shell(
content: Box<dyn Element>,
has_highlighted_border: bool,
should_remove_bottom_margin: bool,
app: &AppContext,
) -> Box<dyn Element> {
let theme = Appearance::as_ref(app).theme();
let border_color = if has_highlighted_border {
theme.accent()
} else {
theme.surface_2()
};
Container::new(content)
.with_margin_left(if has_highlighted_border {
CONTENT_HORIZONTAL_PADDING
} else {
CONTENT_HORIZONTAL_PADDING + icon_size(app) + 16.
})
.with_margin_right(CONTENT_HORIZONTAL_PADDING)
.with_margin_bottom(if should_remove_bottom_margin {
0.
} else {
CONTENT_ITEM_VERTICAL_MARGIN
})
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(8.)))
.with_border(Border::all(1.).with_border_fill(border_color))
.finish()
}