@@ -20,6 +20,7 @@ use gpui::{
};
use language::LanguageRegistry;
use language_model::{LanguageModelProviderTosView, LanguageModelRegistry};
+use language_model_selector::ToggleModelSelector;
use project::Project;
use prompt_library::{PromptLibrary, open_prompt_library};
use prompt_store::PromptBuilder;
@@ -40,7 +41,7 @@ use crate::thread_history::{PastContext, PastThread, ThreadHistory};
use crate::thread_store::ThreadStore;
use crate::{
AssistantDiff, InlineAssistant, NewPromptEditor, NewThread, OpenActiveThreadAsMarkdown,
- OpenAssistantDiff, OpenConfiguration, OpenHistory,
+ OpenAssistantDiff, OpenConfiguration, OpenHistory, ToggleContextPicker,
};
action_with_deprecated_aliases!(
@@ -830,66 +831,150 @@ impl AssistantPanel {
.history_store
.update(cx, |this, cx| this.recent_entries(6, cx));
- let create_welcome_heading = || {
- h_flex()
- .w_full()
- .child(Headline::new("Welcome to the Assistant Panel").size(HeadlineSize::Small))
- };
-
let configuration_error = self.configuration_error(cx);
let no_error = configuration_error.is_none();
+ let focus_handle = self.focus_handle(cx);
v_flex()
- .p_1p5()
.size_full()
- .justify_end()
- .gap_1()
- .map(|parent| {
- match configuration_error {
- Some(ConfigurationError::ProviderNotAuthenticated)
- | Some(ConfigurationError::NoProvider) => {
- parent.child(
- v_flex()
- .px_1p5()
- .gap_0p5()
- .child(create_welcome_heading())
- .child(
- Label::new(
- "To start using the assistant, configure at least one LLM provider.",
- )
- .color(Color::Muted),
- )
- .child(
- h_flex().mt_1().w_full().child(
- Button::new("open-configuration", "Configure a Provider")
- .size(ButtonSize::Compact)
- .icon(Some(IconName::Sliders))
- .icon_size(IconSize::Small)
- .icon_position(IconPosition::Start)
- .on_click(cx.listener(|this, _, window, cx| {
- this.open_configuration(window, cx);
- })),
- ),
- ),
- )
- }
- Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => parent
- .child(v_flex().px_1p5().gap_0p5().child(create_welcome_heading()).children(
- provider.render_accept_terms(
- LanguageModelProviderTosView::ThreadEmptyState,
- cx,
+ .when(recent_history.is_empty(), |this| {
+ this.child(
+ v_flex()
+ .size_full()
+ .max_w_80()
+ .mx_auto()
+ .justify_center()
+ .items_center()
+ .gap_1()
+ .child(
+ h_flex().child(
+ Headline::new("Welcome to the Assistant Panel")
),
- )),
- None => parent,
- }
- })
- .when(recent_history.is_empty() && no_error, |parent| {
- parent.child(v_flex().gap_0p5().child(create_welcome_heading()).child(
- Label::new("Start typing to chat with your codebase").color(Color::Muted),
- ))
+ )
+ .when(no_error, |parent| {
+ parent.child(
+ h_flex().child(
+ Label::new("Ask and build anything.")
+ .color(Color::Muted)
+ .mb_2p5(),
+ ),
+ )
+ .child(
+ Button::new("new-thread", "Start New Thread")
+ .icon(IconName::Plus)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .full_width()
+ .key_binding(KeyBinding::for_action_in(
+ &NewThread,
+ &focus_handle,
+ window,
+ cx,
+ ))
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(NewThread.boxed_clone(), cx)
+ }),
+ )
+ .child(
+ Button::new("context", "Add Context")
+ .icon(IconName::FileCode)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .full_width()
+ .key_binding(KeyBinding::for_action_in(
+ &ToggleContextPicker,
+ &focus_handle,
+ window,
+ cx,
+ ))
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(ToggleContextPicker.boxed_clone(), cx)
+ }),
+ )
+ .child(
+ Button::new("mode", "Switch Model")
+ .icon(IconName::DatabaseZap)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .full_width()
+ .key_binding(KeyBinding::for_action_in(
+ &ToggleModelSelector,
+ &focus_handle,
+ window,
+ cx,
+ ))
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(ToggleModelSelector.boxed_clone(), cx)
+ }),
+ )
+ .child(
+ Button::new("settings", "View Settings")
+ .icon(IconName::Settings)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .full_width()
+ .key_binding(KeyBinding::for_action_in(
+ &OpenConfiguration,
+ &focus_handle,
+ window,
+ cx,
+ ))
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(OpenConfiguration.boxed_clone(), cx)
+ }),
+ )
+ })
+ .map(|parent| {
+ match configuration_error {
+ Some(ConfigurationError::ProviderNotAuthenticated)
+ | Some(ConfigurationError::NoProvider) => {
+ parent
+ .child(
+ h_flex().child(
+ Label::new("To start using the assistant, configure at least one LLM provider.")
+ .color(Color::Muted)
+ .mb_2p5()
+ )
+ )
+ .child(
+ Button::new("settings", "Configure a Provider")
+ .icon(IconName::Settings)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .full_width()
+ .key_binding(KeyBinding::for_action_in(
+ &OpenConfiguration,
+ &focus_handle,
+ window,
+ cx,
+ ))
+ .on_click(|_event, window, cx| {
+ window.dispatch_action(OpenConfiguration.boxed_clone(), cx)
+ }),
+ )
+ }
+ Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => parent
+ .children(
+ provider.render_accept_terms(
+ LanguageModelProviderTosView::ThreadEmptyState,
+ cx,
+ ),
+ ),
+ None => parent,
+ }
+ })
+ )
})
.when(!recent_history.is_empty(), |parent| {
parent
+ .p_1p5()
+ .justify_end()
+ .gap_1()
.child(
h_flex()
.pl_1p5()
@@ -912,7 +997,7 @@ impl AssistantPanel {
&self.focus_handle(cx),
window,
cx,
- ))
+ ).map(|kb| kb.size(rems_from_px(12.))),)
.on_click(move |_event, window, cx| {
window.dispatch_action(OpenHistory.boxed_clone(), cx);
}),
@@ -920,7 +1005,7 @@ impl AssistantPanel {
)
.child(v_flex().gap_1().children(
recent_history.into_iter().map(|entry| {
- // TODO: Add keyboard navigation.
+ // TODO: Add keyboard navigation.
match entry {
HistoryEntry::Thread(thread) => {
PastThread::new(thread, cx.entity().downgrade(), false)
@@ -410,7 +410,11 @@ fn render_accept_terms(
.icon_size(IconSize::XSmall)
.on_click(move |_, _window, cx| cx.open_url("https://zed.dev/terms-of-service"));
- let text = "To start using Zed AI, please read and accept the";
+ let thread_view = match view_kind {
+ LanguageModelProviderTosView::ThreadEmptyState => true,
+ LanguageModelProviderTosView::PromptEditorPopup => false,
+ LanguageModelProviderTosView::Configuration => false,
+ };
let form = v_flex()
.w_full()
@@ -418,14 +422,20 @@ fn render_accept_terms(
.child(
h_flex()
.flex_wrap()
- .items_start()
- .child(Label::new(text))
+ .when(thread_view, |this| this.justify_center())
+ .child(Label::new(
+ "To start using Zed AI, please read and accept the",
+ ))
.child(terms_button),
)
.child({
let button_container = h_flex().w_full().child(
Button::new("accept_terms", "I accept the Terms of Service")
.style(ButtonStyle::Tinted(TintColor::Accent))
+ .icon(IconName::Check)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Small)
+ .full_width()
.disabled(accept_terms_disabled)
.on_click({
let state = state.downgrade();
@@ -439,10 +449,8 @@ fn render_accept_terms(
match view_kind {
LanguageModelProviderTosView::PromptEditorPopup => button_container.justify_end(),
- LanguageModelProviderTosView::Configuration
- | LanguageModelProviderTosView::ThreadEmptyState => {
- button_container.justify_start()
- }
+ LanguageModelProviderTosView::Configuration => button_container.justify_start(),
+ LanguageModelProviderTosView::ThreadEmptyState => button_container.justify_center(),
}
});