Cargo.lock 🔗
@@ -458,6 +458,8 @@ dependencies = [
"command_palette_hooks",
"feature_flags",
"gpui",
+ "language_model",
+ "language_model_selector",
"proto",
"ui",
"workspace",
Marshall Bowers created
This PR sketches in the toolbar for `assistant2`.
<img width="1136" alt="Screenshot 2024-11-23 at 12 39 49 PM"
src="https://github.com/user-attachments/assets/ed56fc36-54c8-48d4-8446-6c1f182fcef2">
Release Notes:
- N/A
Cargo.lock | 2
crates/assistant2/Cargo.toml | 2
crates/assistant2/src/assistant.rs | 2
crates/assistant2/src/assistant_panel.rs | 125 +++++++++++++++++++++++++
4 files changed, 126 insertions(+), 5 deletions(-)
@@ -458,6 +458,8 @@ dependencies = [
"command_palette_hooks",
"feature_flags",
"gpui",
+ "language_model",
+ "language_model_selector",
"proto",
"ui",
"workspace",
@@ -17,6 +17,8 @@ anyhow.workspace = true
command_palette_hooks.workspace = true
feature_flags.workspace = true
gpui.workspace = true
+language_model.workspace = true
+language_model_selector.workspace = true
proto.workspace = true
ui.workspace = true
workspace.workspace = true
@@ -6,7 +6,7 @@ use gpui::{actions, AppContext};
pub use crate::assistant_panel::AssistantPanel;
-actions!(assistant2, [ToggleFocus, NewChat]);
+actions!(assistant2, [ToggleFocus, NewChat, ToggleModelSelector]);
const NAMESPACE: &str = "assistant2";
@@ -3,11 +3,13 @@ use gpui::{
prelude::*, px, Action, AppContext, AsyncWindowContext, EventEmitter, FocusHandle,
FocusableView, Pixels, Task, View, ViewContext, WeakView, WindowContext,
};
-use ui::prelude::*;
+use language_model::LanguageModelRegistry;
+use language_model_selector::LanguageModelSelector;
+use ui::{prelude::*, ButtonLike, Divider, IconButtonShape, Tab, Tooltip};
use workspace::dock::{DockPosition, Panel, PanelEvent};
use workspace::{Pane, Workspace};
-use crate::{NewChat, ToggleFocus};
+use crate::{NewChat, ToggleFocus, ToggleModelSelector};
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(
@@ -116,8 +118,123 @@ impl Panel for AssistantPanel {
}
}
+impl AssistantPanel {
+ fn render_toolbar(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+ let focus_handle = self.focus_handle(cx);
+
+ h_flex()
+ .id("assistant-toolbar")
+ .justify_between()
+ .gap(DynamicSpacing::Base08.rems(cx))
+ .h(Tab::container_height(cx))
+ .px(DynamicSpacing::Base08.rems(cx))
+ .bg(cx.theme().colors().tab_bar_background)
+ .border_b_1()
+ .border_color(cx.theme().colors().border_variant)
+ .child(h_flex().child(Label::new("Chat Title Goes Here")))
+ .child(
+ h_flex()
+ .gap(DynamicSpacing::Base08.rems(cx))
+ .child(self.render_language_model_selector(cx))
+ .child(Divider::vertical())
+ .child(
+ IconButton::new("new-chat", IconName::Plus)
+ .shape(IconButtonShape::Square)
+ .icon_size(IconSize::Small)
+ .style(ButtonStyle::Subtle)
+ .tooltip({
+ let focus_handle = focus_handle.clone();
+ move |cx| {
+ Tooltip::for_action_in("New Chat", &NewChat, &focus_handle, cx)
+ }
+ })
+ .on_click(move |_event, _cx| {
+ println!("New Chat");
+ }),
+ )
+ .child(
+ IconButton::new("open-history", IconName::HistoryRerun)
+ .shape(IconButtonShape::Square)
+ .icon_size(IconSize::Small)
+ .style(ButtonStyle::Subtle)
+ .tooltip(move |cx| Tooltip::text("Open History", cx))
+ .on_click(move |_event, _cx| {
+ println!("Open History");
+ }),
+ )
+ .child(
+ IconButton::new("configure-assistant", IconName::Settings)
+ .shape(IconButtonShape::Square)
+ .icon_size(IconSize::Small)
+ .style(ButtonStyle::Subtle)
+ .tooltip(move |cx| Tooltip::text("Configure Assistant", cx))
+ .on_click(move |_event, _cx| {
+ println!("Configure Assistant");
+ }),
+ ),
+ )
+ }
+
+ fn render_language_model_selector(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+ let active_provider = LanguageModelRegistry::read_global(cx).active_provider();
+ let active_model = LanguageModelRegistry::read_global(cx).active_model();
+
+ LanguageModelSelector::new(
+ |model, _cx| {
+ println!("Selected {:?}", model.name());
+ },
+ ButtonLike::new("active-model")
+ .style(ButtonStyle::Subtle)
+ .child(
+ h_flex()
+ .w_full()
+ .gap_0p5()
+ .child(
+ div()
+ .overflow_x_hidden()
+ .flex_grow()
+ .whitespace_nowrap()
+ .child(match (active_provider, active_model) {
+ (Some(provider), Some(model)) => h_flex()
+ .gap_1()
+ .child(
+ Icon::new(
+ model.icon().unwrap_or_else(|| provider.icon()),
+ )
+ .color(Color::Muted)
+ .size(IconSize::XSmall),
+ )
+ .child(
+ Label::new(model.name().0)
+ .size(LabelSize::Small)
+ .color(Color::Muted),
+ )
+ .into_any_element(),
+ _ => Label::new("No model selected")
+ .size(LabelSize::Small)
+ .color(Color::Muted)
+ .into_any_element(),
+ }),
+ )
+ .child(
+ Icon::new(IconName::ChevronDown)
+ .color(Color::Muted)
+ .size(IconSize::XSmall),
+ ),
+ )
+ .tooltip(move |cx| Tooltip::for_action("Change Model", &ToggleModelSelector, cx)),
+ )
+ }
+}
+
impl Render for AssistantPanel {
- fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
- div().child(Label::new("Assistant II"))
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+ v_flex()
+ .key_context("AssistantPanel2")
+ .size_full()
+ .on_action(cx.listener(|_this, _: &NewChat, _cx| {
+ println!("Action: New Chat");
+ }))
+ .child(self.render_toolbar(cx))
}
}