manage_profiles_modal.rs

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