agent_ui: Fix scrolling in context server configuration modal (#42502)

R.Amogh and Finn Evers created

## Summary

Fixes #42342

When installing a dev extension with long installation instructions, the
configuration modal would overflow and users couldn't scroll to see the
full content or interact with buttons at the bottom.

## Solution

This PR adds a `ScrollHandle` to the `ConfigureContextServerModal` and
passes it to the `Modal` component, enabling the built-in modal
scrolling capability. This ensures all content remains accessible
regardless of length.

## Changes

- Added `ScrollHandle` import to the ui imports
- Added `scroll_handle: ScrollHandle` field to
`ConfigureContextServerModal` struct
- Initialize `scroll_handle` with `ScrollHandle::new()` when creating
the modal
- Pass the scroll handle to `Modal::new()` instead of `None`

## Testing

- Built the changes locally
- Tested with extensions that have long installation instructions
- Verified scrolling works and all content is accessible
- Confirmed no regression for extensions with short descriptions

Release Notes:

- Fixed scrolling issue in extension configuration modal when
installation instructions overflow the viewport

---------

Co-authored-by: Finn Evers <finn.evers@outlook.de>

Change summary

crates/agent_ui/src/agent_configuration/configure_context_server_modal.rs | 41 
1 file changed, 30 insertions(+), 11 deletions(-)

Detailed changes

crates/agent_ui/src/agent_configuration/configure_context_server_modal.rs 🔗

@@ -7,8 +7,8 @@ use anyhow::{Context as _, Result};
 use context_server::{ContextServerCommand, ContextServerId};
 use editor::{Editor, EditorElement, EditorStyle};
 use gpui::{
-    AsyncWindowContext, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Task,
-    TextStyle, TextStyleRefinement, UnderlineStyle, WeakEntity, prelude::*,
+    AsyncWindowContext, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, ScrollHandle,
+    Task, TextStyle, TextStyleRefinement, UnderlineStyle, WeakEntity, prelude::*,
 };
 use language::{Language, LanguageRegistry};
 use markdown::{Markdown, MarkdownElement, MarkdownStyle};
@@ -23,7 +23,8 @@ use project::{
 use settings::{Settings as _, update_settings_file};
 use theme::ThemeSettings;
 use ui::{
-    CommonAnimationExt, KeyBinding, Modal, ModalFooter, ModalHeader, Section, Tooltip, prelude::*,
+    CommonAnimationExt, KeyBinding, Modal, ModalFooter, ModalHeader, Section, Tooltip,
+    WithScrollbar, prelude::*,
 };
 use util::ResultExt as _;
 use workspace::{ModalView, Workspace};
@@ -252,6 +253,7 @@ pub struct ConfigureContextServerModal {
     source: ConfigurationSource,
     state: State,
     original_server_id: Option<ContextServerId>,
+    scroll_handle: ScrollHandle,
 }
 
 impl ConfigureContextServerModal {
@@ -361,6 +363,7 @@ impl ConfigureContextServerModal {
                         window,
                         cx,
                     ),
+                    scroll_handle: ScrollHandle::new(),
                 })
             })
         })
@@ -680,6 +683,7 @@ impl ConfigureContextServerModal {
 
 impl Render for ConfigureContextServerModal {
     fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+        let scroll_handle = self.scroll_handle.clone();
         div()
             .elevation_3(cx)
             .w(rems(34.))
@@ -699,14 +703,29 @@ impl Render for ConfigureContextServerModal {
                 Modal::new("configure-context-server", None)
                     .header(self.render_modal_header())
                     .section(
-                        Section::new()
-                            .child(self.render_modal_description(window, cx))
-                            .child(self.render_modal_content(cx))
-                            .child(match &self.state {
-                                State::Idle => div(),
-                                State::Waiting => Self::render_waiting_for_context_server(),
-                                State::Error(error) => Self::render_modal_error(error.clone()),
-                            }),
+                        Section::new().child(
+                            div()
+                                .size_full()
+                                .child(
+                                    div()
+                                        .id("modal-content")
+                                        .max_h(vh(0.7, window))
+                                        .overflow_y_scroll()
+                                        .track_scroll(&scroll_handle)
+                                        .child(self.render_modal_description(window, cx))
+                                        .child(self.render_modal_content(cx))
+                                        .child(match &self.state {
+                                            State::Idle => div(),
+                                            State::Waiting => {
+                                                Self::render_waiting_for_context_server()
+                                            }
+                                            State::Error(error) => {
+                                                Self::render_modal_error(error.clone())
+                                            }
+                                        }),
+                                )
+                                .vertical_scrollbar_for(scroll_handle, window, cx),
+                        ),
                     )
                     .footer(self.render_modal_footer(cx)),
             )