ui: Make long Callout descriptions scrollable (#45792)

Ahmed Hesham Abdelkader and Danilo Leal created

Fixes #43306

Long error messages from LLM providers in the Agent Panel were not
scrollable, making it impossible to read the full error content.

Changes:
- Add max_h_48() and overflow_y_scroll() to description containers
- Add element IDs required for scroll functionality
- Add min_h_0() and overflow_hidden() to parent flex container
- Add component preview example demonstrating scrollable content

Release Notes:

- Fixed long error messages in Agent Panel being unreadable by making
them scrollable
([#43306](https://github.com/zed-industries/zed/issues/43306)).

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>

Change summary

crates/ui/src/components/callout.rs | 55 ++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 11 deletions(-)

Detailed changes

crates/ui/src/components/callout.rs 🔗

@@ -164,6 +164,7 @@ impl RenderOnce for Callout {
             .child(
                 v_flex()
                     .min_w_0()
+                    .min_h_0()
                     .w_full()
                     .child(
                         h_flex()
@@ -189,20 +190,19 @@ impl RenderOnce for Callout {
                             }),
                     )
                     .map(|this| {
+                        let base_desc_container = div()
+                            .id("callout-description-slot")
+                            .w_full()
+                            .max_h_32()
+                            .flex_1()
+                            .overflow_y_scroll()
+                            .text_ui_sm(cx);
+
                         if let Some(description_slot) = self.description_slot {
-                            this.child(
-                                div()
-                                    .w_full()
-                                    .flex_1()
-                                    .text_ui_sm(cx)
-                                    .child(description_slot),
-                            )
+                            this.child(base_desc_container.child(description_slot))
                         } else if let Some(description) = self.description {
                             this.child(
-                                div()
-                                    .w_full()
-                                    .flex_1()
-                                    .text_ui_sm(cx)
+                                base_desc_container
                                     .text_color(cx.theme().colors().text_muted)
                                     .child(description),
                             )
@@ -276,6 +276,39 @@ impl Component for Callout {
                     .into_any_element(),
             )
             .width(px(580.)),
+            single_example(
+                "Scrollable Long Description",
+                Callout::new()
+                    .severity(Severity::Error)
+                    .icon(IconName::XCircle)
+                    .title("Very Long API Error Description")
+                    .description_slot(
+                        v_flex().gap_1().children(
+                            [
+                                "You exceeded your current quota.",
+                                "For more information, visit the docs.",
+                                "Error details:",
+                                "• Quota exceeded for metric",
+                                "• Limit: 0",
+                                "• Model: gemini-3-pro",
+                                "Please retry in 26.33s.",
+                                "Additional details:",
+                                "- Request ID: abc123def456",
+                                "- Timestamp: 2024-01-15T10:30:00Z",
+                                "- Region: us-central1",
+                                "- Service: generativelanguage.googleapis.com",
+                                "- Error Code: RESOURCE_EXHAUSTED",
+                                "- Retry After: 26s",
+                                "This error occurs when you have exceeded your API quota.",
+                            ]
+                            .into_iter()
+                            .map(|t| Label::new(t).size(LabelSize::Small).color(Color::Muted)),
+                        ),
+                    )
+                    .actions_slot(single_action())
+                    .into_any_element(),
+            )
+            .width(px(580.)),
         ];
 
         let severity_examples = vec![