Files
galaxy/app/src/terminal/rich_history.rs
T

188 lines
5.8 KiB
Rust

use crate::input_suggestions::AIQueryHistoryEntryDetails;
use std::{borrow::Cow, ops::Sub};
use galaxyui::{
elements::{
Align, ConstrainedBox, Container, CrossAxisAlignment, Flex, Icon, ParentElement, Shrinkable,
},
ui_components::components::{Coords, UiComponent, UiComponentStyles},
AppContext, Element, SingletonEntity,
};
use super::HistoryEntry;
use crate::{
appearance::Appearance,
ui_components::icons::Icon as UiIcon,
util::time_format::{format_approx_duration_from_now, human_readable_precise_duration},
};
/// Vertical spacing between line items in rich history details.
pub(crate) const DETAILS_PARAGRAPH_SPACING: f32 = 8.;
/// Renders the details panel for rich history items. One of the items, the linked workflow name,
/// can be enabled/disabled since we only want it for some views and not others.
pub fn render_rich_history(entry: &HistoryEntry, ctx: &AppContext) -> Box<dyn Element> {
let appearance = Appearance::as_ref(ctx);
let ui_builder = appearance.ui_builder();
let mut flex_column = Flex::column().with_cross_axis_alignment(CrossAxisAlignment::Stretch);
if let Some(workflow) = entry.linked_workflow(ctx) {
flex_column.add_child(render_row_with_icon_and_paragraph(
"bundled/svg/workflow.svg",
workflow.name().to_owned(),
appearance,
))
}
if let Some(exit_code) = entry.exit_code {
let icon = if exit_code.was_successful() {
UiIcon::CheckSkinny
} else {
UiIcon::AlertTriangle
};
flex_column.add_child(
Container::new(render_row_with_icon_and_paragraph(
icon.into(),
format!("Exit code {}", exit_code.value()),
appearance,
))
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
if let Some(pwd) = &entry.pwd {
flex_column.add_child(
Container::new(render_row_with_icon_and_paragraph(
UiIcon::Folder.into(),
pwd.clone(),
appearance,
))
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
if let Some(git_head) = &entry.git_head {
flex_column.add_child(
Container::new(render_row_with_icon_and_paragraph(
UiIcon::GitBranch.into(),
git_head.clone(),
appearance,
))
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
if let (Some(start_ts), Some(completed_ts)) = (entry.start_ts, entry.completed_ts) {
flex_column.add_child(
Container::new(
ui_builder
.paragraph(format!(
"Finished in {}",
human_readable_precise_duration((completed_ts).sub(start_ts))
))
.build()
.finish(),
)
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
if let Some(start_ts) = entry.start_ts {
flex_column.add_child(
Container::new(
ui_builder
.paragraph(format!(
"Last ran {}",
format_approx_duration_from_now(start_ts)
))
.build()
.finish(),
)
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
flex_column.finish()
}
pub(crate) fn render_ai_query_rich_history(
entry: &AIQueryHistoryEntryDetails,
ctx: &AppContext,
) -> Box<dyn Element> {
let appearance = Appearance::as_ref(ctx);
let mut details_column = Flex::column()
.with_cross_axis_alignment(CrossAxisAlignment::Stretch)
.with_child(render_row_with_icon_and_paragraph(
entry.output_status.icon().into(),
entry.output_status.display_text(),
appearance,
));
if let Some(working_directory) = &entry.working_directory {
details_column.add_child(
Container::new(render_row_with_icon_and_paragraph(
UiIcon::Folder.into(),
working_directory.clone(),
appearance,
))
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
}
details_column.add_child(
Container::new(
appearance
.ui_builder()
.paragraph(format!(
"Ran {}",
format_approx_duration_from_now(entry.start_time)
))
.build()
.finish(),
)
.with_margin_top(DETAILS_PARAGRAPH_SPACING)
.finish(),
);
details_column.finish()
}
pub(crate) fn render_row_with_icon_and_paragraph(
icon_path: &'static str,
text: impl Into<Cow<'static, str>>,
appearance: &Appearance,
) -> Box<dyn Element> {
Flex::row()
.with_children([
ConstrainedBox::new(Icon::new(icon_path, appearance.theme().foreground()).finish())
.with_max_height(appearance.ui_font_size())
.with_max_width(appearance.ui_font_size())
.finish(),
Shrinkable::new(
1.,
Align::new(
appearance
.ui_builder()
.paragraph(text)
.with_style(UiComponentStyles {
margin: Some(Coords::uniform(0.).left(4.)),
..Default::default()
})
.build()
.finish(),
)
.left()
.finish(),
)
.finish(),
])
.finish()
}