manage_profiles_modal.rs

  1mod profile_modal_header;
  2
  3use std::sync::Arc;
  4
  5use agent::ContextServerRegistry;
  6use agent_settings::{AgentProfile, AgentProfileId, AgentSettings, builtin_profiles};
  7use editor::Editor;
  8use fs::Fs;
  9use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Subscription, prelude::*};
 10use settings::Settings as _;
 11use ui::{
 12    KeyBinding, ListItem, ListItemSpacing, ListSeparator, Navigable, NavigableEntry, prelude::*,
 13};
 14use workspace::{ModalView, Workspace};
 15
 16use crate::agent_configuration::manage_profiles_modal::profile_modal_header::ProfileModalHeader;
 17use crate::agent_configuration::tool_picker::{ToolPicker, ToolPickerDelegate};
 18use crate::{AgentPanel, ManageProfiles};
 19
 20enum Mode {
 21    ChooseProfile(ChooseProfileMode),
 22    NewProfile(NewProfileMode),
 23    ViewProfile(ViewProfileMode),
 24    ConfigureTools {
 25        profile_id: AgentProfileId,
 26        tool_picker: Entity<ToolPicker>,
 27        _subscription: Subscription,
 28    },
 29    ConfigureMcps {
 30        profile_id: AgentProfileId,
 31        tool_picker: Entity<ToolPicker>,
 32        _subscription: Subscription,
 33    },
 34}
 35
 36impl Mode {
 37    pub fn choose_profile(_window: &mut Window, cx: &mut Context<ManageProfilesModal>) -> Self {
 38        let settings = AgentSettings::get_global(cx);
 39
 40        let mut builtin_profiles = Vec::new();
 41        let mut custom_profiles = Vec::new();
 42
 43        for (profile_id, profile) in settings.profiles.iter() {
 44            let entry = ProfileEntry {
 45                id: profile_id.clone(),
 46                name: profile.name.clone(),
 47                navigation: NavigableEntry::focusable(cx),
 48            };
 49            if builtin_profiles::is_builtin(profile_id) {
 50                builtin_profiles.push(entry);
 51            } else {
 52                custom_profiles.push(entry);
 53            }
 54        }
 55
 56        builtin_profiles.sort_unstable_by(|a, b| a.name.cmp(&b.name));
 57        custom_profiles.sort_unstable_by(|a, b| a.name.cmp(&b.name));
 58
 59        Self::ChooseProfile(ChooseProfileMode {
 60            builtin_profiles,
 61            custom_profiles,
 62            add_new_profile: NavigableEntry::focusable(cx),
 63        })
 64    }
 65}
 66
 67#[derive(Clone)]
 68struct ProfileEntry {
 69    pub id: AgentProfileId,
 70    pub name: SharedString,
 71    pub navigation: NavigableEntry,
 72}
 73
 74#[derive(Clone)]
 75pub struct ChooseProfileMode {
 76    builtin_profiles: Vec<ProfileEntry>,
 77    custom_profiles: Vec<ProfileEntry>,
 78    add_new_profile: NavigableEntry,
 79}
 80
 81#[derive(Clone)]
 82pub struct ViewProfileMode {
 83    profile_id: AgentProfileId,
 84    fork_profile: NavigableEntry,
 85    configure_tools: NavigableEntry,
 86    configure_mcps: NavigableEntry,
 87    cancel_item: NavigableEntry,
 88}
 89
 90#[derive(Clone)]
 91pub struct NewProfileMode {
 92    name_editor: Entity<Editor>,
 93    base_profile_id: Option<AgentProfileId>,
 94}
 95
 96pub struct ManageProfilesModal {
 97    fs: Arc<dyn Fs>,
 98    context_server_registry: Entity<ContextServerRegistry>,
 99    focus_handle: FocusHandle,
100    mode: Mode,
101}
102
103impl ManageProfilesModal {
104    pub fn register(
105        workspace: &mut Workspace,
106        _window: Option<&mut Window>,
107        _cx: &mut Context<Workspace>,
108    ) {
109        workspace.register_action(|workspace, action: &ManageProfiles, window, cx| {
110            if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
111                let fs = workspace.app_state().fs.clone();
112                let context_server_registry = panel.read(cx).context_server_registry().clone();
113                workspace.toggle_modal(window, cx, |window, cx| {
114                    let mut this = Self::new(fs, context_server_registry, window, cx);
115
116                    if let Some(profile_id) = action.customize_tools.clone() {
117                        this.configure_builtin_tools(profile_id, window, cx);
118                    }
119
120                    this
121                })
122            }
123        });
124    }
125
126    pub fn new(
127        fs: Arc<dyn Fs>,
128        context_server_registry: Entity<ContextServerRegistry>,
129        window: &mut Window,
130        cx: &mut Context<Self>,
131    ) -> Self {
132        let focus_handle = cx.focus_handle();
133
134        Self {
135            fs,
136            context_server_registry,
137            focus_handle,
138            mode: Mode::choose_profile(window, cx),
139        }
140    }
141
142    fn choose_profile(&mut self, window: &mut Window, cx: &mut Context<Self>) {
143        self.mode = Mode::choose_profile(window, cx);
144        self.focus_handle(cx).focus(window);
145    }
146
147    fn new_profile(
148        &mut self,
149        base_profile_id: Option<AgentProfileId>,
150        window: &mut Window,
151        cx: &mut Context<Self>,
152    ) {
153        let name_editor = cx.new(|cx| Editor::single_line(window, cx));
154        name_editor.update(cx, |editor, cx| {
155            editor.set_placeholder_text("Profile name", window, cx);
156        });
157
158        self.mode = Mode::NewProfile(NewProfileMode {
159            name_editor,
160            base_profile_id,
161        });
162        self.focus_handle(cx).focus(window);
163    }
164
165    pub fn view_profile(
166        &mut self,
167        profile_id: AgentProfileId,
168        window: &mut Window,
169        cx: &mut Context<Self>,
170    ) {
171        self.mode = Mode::ViewProfile(ViewProfileMode {
172            profile_id,
173            fork_profile: NavigableEntry::focusable(cx),
174            configure_tools: NavigableEntry::focusable(cx),
175            configure_mcps: NavigableEntry::focusable(cx),
176            cancel_item: NavigableEntry::focusable(cx),
177        });
178        self.focus_handle(cx).focus(window);
179    }
180
181    fn configure_mcp_tools(
182        &mut self,
183        profile_id: AgentProfileId,
184        window: &mut Window,
185        cx: &mut Context<Self>,
186    ) {
187        let settings = AgentSettings::get_global(cx);
188        let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
189            return;
190        };
191
192        let tool_picker = cx.new(|cx| {
193            let delegate = ToolPickerDelegate::mcp_tools(
194                &self.context_server_registry,
195                self.fs.clone(),
196                profile_id.clone(),
197                profile,
198                cx,
199            );
200            ToolPicker::mcp_tools(delegate, window, cx)
201        });
202        let dismiss_subscription = cx.subscribe_in(&tool_picker, window, {
203            let profile_id = profile_id.clone();
204            move |this, _tool_picker, _: &DismissEvent, window, cx| {
205                this.view_profile(profile_id.clone(), window, cx);
206            }
207        });
208
209        self.mode = Mode::ConfigureMcps {
210            profile_id,
211            tool_picker,
212            _subscription: dismiss_subscription,
213        };
214        self.focus_handle(cx).focus(window);
215    }
216
217    fn configure_builtin_tools(
218        &mut self,
219        profile_id: AgentProfileId,
220        window: &mut Window,
221        cx: &mut Context<Self>,
222    ) {
223        let settings = AgentSettings::get_global(cx);
224        let Some(profile) = settings.profiles.get(&profile_id).cloned() else {
225            return;
226        };
227
228        let tool_picker = cx.new(|cx| {
229            let delegate = ToolPickerDelegate::builtin_tools(
230                //todo: This causes the web search tool to show up even it only works when using zed hosted models
231                agent::built_in_tool_names()
232                    .map(|s| s.into())
233                    .collect::<Vec<_>>(),
234                self.fs.clone(),
235                profile_id.clone(),
236                profile,
237                cx,
238            );
239            ToolPicker::builtin_tools(delegate, window, cx)
240        });
241        let dismiss_subscription = cx.subscribe_in(&tool_picker, window, {
242            let profile_id = profile_id.clone();
243            move |this, _tool_picker, _: &DismissEvent, window, cx| {
244                this.view_profile(profile_id.clone(), window, cx);
245            }
246        });
247
248        self.mode = Mode::ConfigureTools {
249            profile_id,
250            tool_picker,
251            _subscription: dismiss_subscription,
252        };
253        self.focus_handle(cx).focus(window);
254    }
255
256    fn confirm(&mut self, window: &mut Window, cx: &mut Context<Self>) {
257        match &self.mode {
258            Mode::ChooseProfile { .. } => {}
259            Mode::NewProfile(mode) => {
260                let name = mode.name_editor.read(cx).text(cx);
261
262                let profile_id =
263                    AgentProfile::create(name, mode.base_profile_id.clone(), self.fs.clone(), cx);
264                self.view_profile(profile_id, window, cx);
265            }
266            Mode::ViewProfile(_) => {}
267            Mode::ConfigureTools { .. } => {}
268            Mode::ConfigureMcps { .. } => {}
269        }
270    }
271
272    fn cancel(&mut self, window: &mut Window, cx: &mut Context<Self>) {
273        match &self.mode {
274            Mode::ChooseProfile { .. } => {
275                cx.emit(DismissEvent);
276            }
277            Mode::NewProfile(mode) => {
278                if let Some(profile_id) = mode.base_profile_id.clone() {
279                    self.view_profile(profile_id, window, cx);
280                } else {
281                    self.choose_profile(window, cx);
282                }
283            }
284            Mode::ViewProfile(_) => self.choose_profile(window, cx),
285            Mode::ConfigureTools { profile_id, .. } => {
286                self.view_profile(profile_id.clone(), window, cx)
287            }
288            Mode::ConfigureMcps { profile_id, .. } => {
289                self.view_profile(profile_id.clone(), window, cx)
290            }
291        }
292    }
293}
294
295impl ModalView for ManageProfilesModal {}
296
297impl Focusable for ManageProfilesModal {
298    fn focus_handle(&self, cx: &App) -> FocusHandle {
299        match &self.mode {
300            Mode::ChooseProfile(_) => self.focus_handle.clone(),
301            Mode::NewProfile(mode) => mode.name_editor.focus_handle(cx),
302            Mode::ViewProfile(_) => self.focus_handle.clone(),
303            Mode::ConfigureTools { tool_picker, .. } => tool_picker.focus_handle(cx),
304            Mode::ConfigureMcps { tool_picker, .. } => tool_picker.focus_handle(cx),
305        }
306    }
307}
308
309impl EventEmitter<DismissEvent> for ManageProfilesModal {}
310
311impl ManageProfilesModal {
312    fn render_profile(
313        &self,
314        profile: &ProfileEntry,
315        window: &mut Window,
316        cx: &mut Context<Self>,
317    ) -> impl IntoElement + use<> {
318        let is_focused = profile.navigation.focus_handle.contains_focused(window, cx);
319
320        div()
321            .id(SharedString::from(format!("profile-{}", profile.id)))
322            .track_focus(&profile.navigation.focus_handle)
323            .on_action({
324                let profile_id = profile.id.clone();
325                cx.listener(move |this, _: &menu::Confirm, window, cx| {
326                    this.view_profile(profile_id.clone(), window, cx);
327                })
328            })
329            .child(
330                ListItem::new(SharedString::from(format!("profile-{}", profile.id)))
331                    .toggle_state(is_focused)
332                    .inset(true)
333                    .spacing(ListItemSpacing::Sparse)
334                    .child(Label::new(profile.name.clone()))
335                    .when(is_focused, |this| {
336                        this.end_slot(
337                            h_flex()
338                                .gap_1()
339                                .child(
340                                    Label::new("Customize")
341                                        .size(LabelSize::Small)
342                                        .color(Color::Muted),
343                                )
344                                .children(KeyBinding::for_action_in(
345                                    &menu::Confirm,
346                                    &self.focus_handle,
347                                    window,
348                                    cx,
349                                )),
350                        )
351                    })
352                    .on_click({
353                        let profile_id = profile.id.clone();
354                        cx.listener(move |this, _, window, cx| {
355                            this.view_profile(profile_id.clone(), window, cx);
356                        })
357                    }),
358            )
359    }
360
361    fn render_choose_profile(
362        &mut self,
363        mode: ChooseProfileMode,
364        window: &mut Window,
365        cx: &mut Context<Self>,
366    ) -> impl IntoElement {
367        Navigable::new(
368            div()
369                .track_focus(&self.focus_handle(cx))
370                .size_full()
371                .child(ProfileModalHeader::new("Agent Profiles", None))
372                .child(
373                    v_flex()
374                        .pb_1()
375                        .child(ListSeparator)
376                        .children(
377                            mode.builtin_profiles
378                                .iter()
379                                .map(|profile| self.render_profile(profile, window, cx)),
380                        )
381                        .when(!mode.custom_profiles.is_empty(), |this| {
382                            this.child(ListSeparator)
383                                .child(
384                                    div().pl_2().pb_1().child(
385                                        Label::new("Custom Profiles")
386                                            .size(LabelSize::Small)
387                                            .color(Color::Muted),
388                                    ),
389                                )
390                                .children(
391                                    mode.custom_profiles
392                                        .iter()
393                                        .map(|profile| self.render_profile(profile, window, cx)),
394                                )
395                        })
396                        .child(ListSeparator)
397                        .child(
398                            div()
399                                .id("new-profile")
400                                .track_focus(&mode.add_new_profile.focus_handle)
401                                .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| {
402                                    this.new_profile(None, window, cx);
403                                }))
404                                .child(
405                                    ListItem::new("new-profile")
406                                        .toggle_state(
407                                            mode.add_new_profile
408                                                .focus_handle
409                                                .contains_focused(window, cx),
410                                        )
411                                        .inset(true)
412                                        .spacing(ListItemSpacing::Sparse)
413                                        .start_slot(Icon::new(IconName::Plus))
414                                        .child(Label::new("Add New Profile"))
415                                        .on_click({
416                                            cx.listener(move |this, _, window, cx| {
417                                                this.new_profile(None, window, cx);
418                                            })
419                                        }),
420                                ),
421                        ),
422                )
423                .into_any_element(),
424        )
425        .map(|mut navigable| {
426            for profile in mode.builtin_profiles {
427                navigable = navigable.entry(profile.navigation);
428            }
429            for profile in mode.custom_profiles {
430                navigable = navigable.entry(profile.navigation);
431            }
432
433            navigable
434        })
435        .entry(mode.add_new_profile)
436    }
437
438    fn render_new_profile(
439        &mut self,
440        mode: NewProfileMode,
441        _window: &mut Window,
442        cx: &mut Context<Self>,
443    ) -> impl IntoElement {
444        let settings = AgentSettings::get_global(cx);
445
446        let base_profile_name = mode.base_profile_id.as_ref().map(|base_profile_id| {
447            settings
448                .profiles
449                .get(base_profile_id)
450                .map(|profile| profile.name.clone())
451                .unwrap_or_else(|| "Unknown".into())
452        });
453
454        v_flex()
455            .id("new-profile")
456            .track_focus(&self.focus_handle(cx))
457            .child(ProfileModalHeader::new(
458                match &base_profile_name {
459                    Some(base_profile) => format!("Fork {base_profile}"),
460                    None => "New Profile".into(),
461                },
462                match base_profile_name {
463                    Some(_) => Some(IconName::Scissors),
464                    None => Some(IconName::Plus),
465                },
466            ))
467            .child(ListSeparator)
468            .child(h_flex().p_2().child(mode.name_editor))
469    }
470
471    fn render_view_profile(
472        &mut self,
473        mode: ViewProfileMode,
474        window: &mut Window,
475        cx: &mut Context<Self>,
476    ) -> impl IntoElement {
477        let settings = AgentSettings::get_global(cx);
478
479        let profile_name = settings
480            .profiles
481            .get(&mode.profile_id)
482            .map(|profile| profile.name.clone())
483            .unwrap_or_else(|| "Unknown".into());
484
485        let icon = match mode.profile_id.as_str() {
486            "write" => IconName::Pencil,
487            "ask" => IconName::Chat,
488            _ => IconName::UserRoundPen,
489        };
490
491        Navigable::new(
492            div()
493                .track_focus(&self.focus_handle(cx))
494                .size_full()
495                .child(ProfileModalHeader::new(profile_name, Some(icon)))
496                .child(
497                    v_flex()
498                        .pb_1()
499                        .child(ListSeparator)
500                        .child(
501                            div()
502                                .id("fork-profile")
503                                .track_focus(&mode.fork_profile.focus_handle)
504                                .on_action({
505                                    let profile_id = mode.profile_id.clone();
506                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
507                                        this.new_profile(Some(profile_id.clone()), window, cx);
508                                    })
509                                })
510                                .child(
511                                    ListItem::new("fork-profile")
512                                        .toggle_state(
513                                            mode.fork_profile
514                                                .focus_handle
515                                                .contains_focused(window, cx),
516                                        )
517                                        .inset(true)
518                                        .spacing(ListItemSpacing::Sparse)
519                                        .start_slot(
520                                            Icon::new(IconName::Scissors)
521                                                .size(IconSize::Small)
522                                                .color(Color::Muted),
523                                        )
524                                        .child(Label::new("Fork Profile"))
525                                        .on_click({
526                                            let profile_id = mode.profile_id.clone();
527                                            cx.listener(move |this, _, window, cx| {
528                                                this.new_profile(
529                                                    Some(profile_id.clone()),
530                                                    window,
531                                                    cx,
532                                                );
533                                            })
534                                        }),
535                                ),
536                        )
537                        .child(
538                            div()
539                                .id("configure-builtin-tools")
540                                .track_focus(&mode.configure_tools.focus_handle)
541                                .on_action({
542                                    let profile_id = mode.profile_id.clone();
543                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
544                                        this.configure_builtin_tools(
545                                            profile_id.clone(),
546                                            window,
547                                            cx,
548                                        );
549                                    })
550                                })
551                                .child(
552                                    ListItem::new("configure-builtin-tools-item")
553                                        .toggle_state(
554                                            mode.configure_tools
555                                                .focus_handle
556                                                .contains_focused(window, cx),
557                                        )
558                                        .inset(true)
559                                        .spacing(ListItemSpacing::Sparse)
560                                        .start_slot(
561                                            Icon::new(IconName::Settings)
562                                                .size(IconSize::Small)
563                                                .color(Color::Muted),
564                                        )
565                                        .child(Label::new("Configure Built-in Tools"))
566                                        .on_click({
567                                            let profile_id = mode.profile_id.clone();
568                                            cx.listener(move |this, _, window, cx| {
569                                                this.configure_builtin_tools(
570                                                    profile_id.clone(),
571                                                    window,
572                                                    cx,
573                                                );
574                                            })
575                                        }),
576                                ),
577                        )
578                        .child(
579                            div()
580                                .id("configure-mcps")
581                                .track_focus(&mode.configure_mcps.focus_handle)
582                                .on_action({
583                                    let profile_id = mode.profile_id.clone();
584                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
585                                        this.configure_mcp_tools(profile_id.clone(), window, cx);
586                                    })
587                                })
588                                .child(
589                                    ListItem::new("configure-mcp-tools")
590                                        .toggle_state(
591                                            mode.configure_mcps
592                                                .focus_handle
593                                                .contains_focused(window, cx),
594                                        )
595                                        .inset(true)
596                                        .spacing(ListItemSpacing::Sparse)
597                                        .start_slot(
598                                            Icon::new(IconName::ToolHammer)
599                                                .size(IconSize::Small)
600                                                .color(Color::Muted),
601                                        )
602                                        .child(Label::new("Configure MCP Tools"))
603                                        .on_click({
604                                            let profile_id = mode.profile_id.clone();
605                                            cx.listener(move |this, _, window, cx| {
606                                                this.configure_mcp_tools(
607                                                    profile_id.clone(),
608                                                    window,
609                                                    cx,
610                                                );
611                                            })
612                                        }),
613                                ),
614                        )
615                        .child(ListSeparator)
616                        .child(
617                            div()
618                                .id("cancel-item")
619                                .track_focus(&mode.cancel_item.focus_handle)
620                                .on_action({
621                                    cx.listener(move |this, _: &menu::Confirm, window, cx| {
622                                        this.cancel(window, cx);
623                                    })
624                                })
625                                .child(
626                                    ListItem::new("cancel-item")
627                                        .toggle_state(
628                                            mode.cancel_item
629                                                .focus_handle
630                                                .contains_focused(window, cx),
631                                        )
632                                        .inset(true)
633                                        .spacing(ListItemSpacing::Sparse)
634                                        .start_slot(
635                                            Icon::new(IconName::ArrowLeft)
636                                                .size(IconSize::Small)
637                                                .color(Color::Muted),
638                                        )
639                                        .child(Label::new("Go Back"))
640                                        .end_slot(
641                                            div().children(
642                                                KeyBinding::for_action_in(
643                                                    &menu::Cancel,
644                                                    &self.focus_handle,
645                                                    window,
646                                                    cx,
647                                                )
648                                                .map(|kb| kb.size(rems_from_px(12.))),
649                                            ),
650                                        )
651                                        .on_click({
652                                            cx.listener(move |this, _, window, cx| {
653                                                this.cancel(window, cx);
654                                            })
655                                        }),
656                                ),
657                        ),
658                )
659                .into_any_element(),
660        )
661        .entry(mode.fork_profile)
662        .entry(mode.configure_tools)
663        .entry(mode.configure_mcps)
664        .entry(mode.cancel_item)
665    }
666}
667
668impl Render for ManageProfilesModal {
669    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
670        let settings = AgentSettings::get_global(cx);
671
672        let go_back_item = div()
673            .id("cancel-item")
674            .track_focus(&self.focus_handle)
675            .on_action({
676                cx.listener(move |this, _: &menu::Confirm, window, cx| {
677                    this.cancel(window, cx);
678                })
679            })
680            .child(
681                ListItem::new("cancel-item")
682                    .toggle_state(self.focus_handle.contains_focused(window, cx))
683                    .inset(true)
684                    .spacing(ListItemSpacing::Sparse)
685                    .start_slot(
686                        Icon::new(IconName::ArrowLeft)
687                            .size(IconSize::Small)
688                            .color(Color::Muted),
689                    )
690                    .child(Label::new("Go Back"))
691                    .end_slot(
692                        div().children(
693                            KeyBinding::for_action_in(
694                                &menu::Cancel,
695                                &self.focus_handle,
696                                window,
697                                cx,
698                            )
699                            .map(|kb| kb.size(rems_from_px(12.))),
700                        ),
701                    )
702                    .on_click({
703                        cx.listener(move |this, _, window, cx| {
704                            this.cancel(window, cx);
705                        })
706                    }),
707            );
708
709        div()
710            .elevation_3(cx)
711            .w(rems(34.))
712            .key_context("ManageProfilesModal")
713            .on_action(cx.listener(|this, _: &menu::Cancel, window, cx| this.cancel(window, cx)))
714            .on_action(cx.listener(|this, _: &menu::Confirm, window, cx| this.confirm(window, cx)))
715            .capture_any_mouse_down(cx.listener(|this, _, window, cx| {
716                this.focus_handle(cx).focus(window);
717            }))
718            .on_mouse_down_out(cx.listener(|_this, _, _, cx| cx.emit(DismissEvent)))
719            .child(match &self.mode {
720                Mode::ChooseProfile(mode) => self
721                    .render_choose_profile(mode.clone(), window, cx)
722                    .into_any_element(),
723                Mode::NewProfile(mode) => self
724                    .render_new_profile(mode.clone(), window, cx)
725                    .into_any_element(),
726                Mode::ViewProfile(mode) => self
727                    .render_view_profile(mode.clone(), window, cx)
728                    .into_any_element(),
729                Mode::ConfigureTools {
730                    profile_id,
731                    tool_picker,
732                    ..
733                } => {
734                    let profile_name = settings
735                        .profiles
736                        .get(profile_id)
737                        .map(|profile| profile.name.clone())
738                        .unwrap_or_else(|| "Unknown".into());
739
740                    v_flex()
741                        .pb_1()
742                        .child(ProfileModalHeader::new(
743                            format!("{profile_name} — Configure Built-in Tools"),
744                            Some(IconName::Cog),
745                        ))
746                        .child(ListSeparator)
747                        .child(tool_picker.clone())
748                        .child(ListSeparator)
749                        .child(go_back_item)
750                        .into_any_element()
751                }
752                Mode::ConfigureMcps {
753                    profile_id,
754                    tool_picker,
755                    ..
756                } => {
757                    let profile_name = settings
758                        .profiles
759                        .get(profile_id)
760                        .map(|profile| profile.name.clone())
761                        .unwrap_or_else(|| "Unknown".into());
762
763                    v_flex()
764                        .pb_1()
765                        .child(ProfileModalHeader::new(
766                            format!("{profile_name} — Configure MCP Tools"),
767                            Some(IconName::ToolHammer),
768                        ))
769                        .child(ListSeparator)
770                        .child(tool_picker.clone())
771                        .child(ListSeparator)
772                        .child(go_back_item)
773                        .into_any_element()
774                }
775            })
776    }
777}