assistant2: Ensure errors are also displayed in populated new thread view (#27869)

Follow-up to https://github.com/zed-industries/zed/pull/27812

This PR makes sure these errors cases also show up in the panel's empty
state even when there is past data.

| No ToS | Missing Provider |
|--------|--------|
| ![CleanShot 2025-04-01 at 4  49
36@2x](https://github.com/user-attachments/assets/6da6bdc9-daa6-4a7b-a224-989eb845e205)
| ![CleanShot 2025-04-01 at 4  50
04@2x](https://github.com/user-attachments/assets/bddf62cb-3727-44b5-b115-9a88313c6d85)
|

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2025-04-01 17:06:34 -03:00 committed by GitHub
parent 92059803fb
commit 192097f58f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 243 additions and 143 deletions

View file

@ -26,7 +26,9 @@ use prompt_library::{PromptLibrary, open_prompt_library};
use prompt_store::PromptBuilder;
use settings::{Settings, update_settings_file};
use time::UtcOffset;
use ui::{ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip, prelude::*};
use ui::{
Banner, ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip, prelude::*,
};
use util::ResultExt as _;
use workspace::Workspace;
use workspace::dock::{DockPosition, Panel, PanelEvent};
@ -838,6 +840,7 @@ impl AssistantPanel {
v_flex()
.size_full()
.when(recent_history.is_empty(), |this| {
let configuration_error_ref = &configuration_error;
this.child(
v_flex()
.size_full()
@ -852,84 +855,85 @@ impl AssistantPanel {
),
)
.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)
}),
)
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 {
match configuration_error_ref {
Some(ConfigurationError::ProviderNotAuthenticated)
| Some(ConfigurationError::NoProvider) => {
parent
@ -958,23 +962,27 @@ impl AssistantPanel {
}),
)
}
Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => parent
.children(
Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => {
parent.children(
provider.render_accept_terms(
LanguageModelProviderTosView::ThreadEmptyState,
LanguageModelProviderTosView::ThreadFreshStart,
cx,
),
),
)
}
None => parent,
}
})
)
})
.when(!recent_history.is_empty(), |parent| {
let focus_handle = focus_handle.clone();
let configuration_error_ref = &configuration_error;
parent
.p_1p5()
.justify_end()
.gap_1()
.justify_end()
.gap_1()
.child(
h_flex()
.pl_1p5()
@ -992,32 +1000,94 @@ impl AssistantPanel {
Button::new("view-history", "View All")
.style(ButtonStyle::Subtle)
.label_size(LabelSize::Small)
.key_binding(KeyBinding::for_action_in(
&OpenHistory,
&self.focus_handle(cx),
window,
cx,
).map(|kb| kb.size(rems_from_px(12.))),)
.key_binding(
KeyBinding::for_action_in(
&OpenHistory,
&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);
}),
),
)
.child(v_flex().gap_1().children(
recent_history.into_iter().map(|entry| {
// TODO: Add keyboard navigation.
match entry {
HistoryEntry::Thread(thread) => {
PastThread::new(thread, cx.entity().downgrade(), false)
.into_any_element()
}
HistoryEntry::Context(context) => {
PastContext::new(context, cx.entity().downgrade(), false)
.into_any_element()
}
.child(
v_flex()
.gap_1()
.children(
recent_history.into_iter().map(|entry| {
// TODO: Add keyboard navigation.
match entry {
HistoryEntry::Thread(thread) => {
PastThread::new(thread, cx.entity().downgrade(), false)
.into_any_element()
}
HistoryEntry::Context(context) => {
PastContext::new(context, cx.entity().downgrade(), false)
.into_any_element()
}
}
}),
)
)
.map(|parent| {
match configuration_error_ref {
Some(ConfigurationError::ProviderNotAuthenticated)
| Some(ConfigurationError::NoProvider) => {
parent
.child(
Banner::new()
.severity(ui::Severity::Warning)
.children(
Label::new(
"Configure at least one LLM provider to start using the panel.",
)
.size(LabelSize::Small),
)
.action_slot(
Button::new("settings", "Configure Provider")
.style(ButtonStyle::Tinted(ui::TintColor::Warning))
.label_size(LabelSize::Small)
.key_binding(
KeyBinding::for_action_in(
&OpenConfiguration,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(|_event, window, cx| {
window.dispatch_action(
OpenConfiguration.boxed_clone(),
cx,
)
}),
),
)
}
}),
))
Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => {
parent
.child(
Banner::new()
.severity(ui::Severity::Warning)
.children(
h_flex()
.w_full()
.children(
provider.render_accept_terms(
LanguageModelProviderTosView::ThreadtEmptyState,
cx,
),
),
),
)
}
None => parent,
}
})
})
}