From ff2e5d48153a1876328feab16bafa7ada5280e11 Mon Sep 17 00:00:00 2001 From: Finn Eitreim <48069764+feitreim@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:15:39 -0400 Subject: [PATCH] settings_ui: Fix edit predictions and tool permissions for narrow windows (#51878) Closes #51865 The Tool Permissions and Edit Prediction Providers pages have settings that do not conform very well to the usual setup, because of this they are specially defined in .../settings_ui/src/pages . Due to this setup, they do not benefit from the same automatic responsive setup as the other parts of the settings ui. This was causing issues w/ narrow windows, where fields and text were extending past the side of the window or just not displaying. All that was needed to fix it was some tweaks to the structure and css of those pages, and its smooth sailing. Maybe in the future `render_settings_item` can be made broader and support these use cases as well so this doesn't have to be handled manually. Behavior Before: https://github.com/user-attachments/assets/283df746-e1bb-4791-b259-085dc83f3292 Behavior After: https://github.com/user-attachments/assets/154c8fcf-8a02-49c8-910a-a69dc11b144f Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [x] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - Settings Editor: Fixed the display issue with narrow windows on the Edit Prediction configuration page. --------- Co-authored-by: Danilo Leal --- .../pages/edit_prediction_provider_setup.rs | 15 ++++++---- .../src/pages/tool_permissions_setup.rs | 21 ++++++++++---- crates/settings_ui/src/settings_ui.rs | 29 +++++++++++-------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/crates/settings_ui/src/pages/edit_prediction_provider_setup.rs b/crates/settings_ui/src/pages/edit_prediction_provider_setup.rs index 32c4bee84bd1f72263ed28bcd44d7e6349c4b24c..736a8e83e34339b3aab18d865938a49f31ba7783 100644 --- a/crates/settings_ui/src/pages/edit_prediction_provider_setup.rs +++ b/crates/settings_ui/src/pages/edit_prediction_provider_setup.rs @@ -99,8 +99,7 @@ pub(crate) fn render_edit_prediction_setup_page( IconName::AiOpenAiCompat, "OpenAI Compatible API", ApiKeyDocs::Custom { - message: "Set an API key here. It will be sent as Authorization: Bearer {key}." - .into(), + message: "The API key sent as Authorization: Bearer {key}.".into(), }, open_ai_compatible_api_token(cx), |cx| open_ai_compatible_api_url(cx), @@ -172,10 +171,12 @@ fn render_provider_dropdown(window: &mut Window, cx: &mut App) -> AnyElement { h_flex() .pt_2p5() .w_full() + .min_w_0() .justify_between() .child( v_flex() .w_full() + .min_w_0() .max_w_1_2() .child(Label::new("Provider")) .child( @@ -246,13 +247,15 @@ fn render_api_key_provider( .no_padding(true); let button_link_label = format!("{} dashboard", title); let description = match docs { - ApiKeyDocs::Custom { message } => h_flex().min_w_0().gap_0p5().child( + ApiKeyDocs::Custom { message } => div().min_w_0().w_full().child( Label::new(message) .size(LabelSize::Small) .color(Color::Muted), ), ApiKeyDocs::Link { dashboard_url } => h_flex() + .w_full() .min_w_0() + .flex_wrap() .gap_0p5() .child( Label::new("Visit the") @@ -300,10 +303,12 @@ fn render_api_key_provider( h_flex() .pt_2p5() .w_full() + .min_w_0() .justify_between() .child( v_flex() .w_full() + .min_w_0() .max_w_1_2() .child(Label::new("API Key")) .child(description) @@ -466,7 +471,7 @@ fn ollama_settings() -> Box<[SettingsPageItem]> { }), SettingsPageItem::SettingItem(SettingItem { title: "Prompt Format", - description: "The prompt format to use when requesting predictions. Set to Infer to have the format inferred based on the model name", + description: "The prompt format to use when requesting predictions. Set to Infer to have the format inferred based on the model name.", field: Box::new(SettingField { pick: |settings| { settings @@ -597,7 +602,7 @@ fn open_ai_compatible_settings() -> Box<[SettingsPageItem]> { }), SettingsPageItem::SettingItem(SettingItem { title: "Prompt Format", - description: "The prompt format to use when requesting predictions. Set to Infer to have the format inferred based on the model name", + description: "The prompt format to use when requesting predictions. Set to Infer to have the format inferred based on the model name.", field: Box::new(SettingField { pick: |settings| { settings diff --git a/crates/settings_ui/src/pages/tool_permissions_setup.rs b/crates/settings_ui/src/pages/tool_permissions_setup.rs index f5f1f0ea7eb71c7af41ba2c60a30b2ec5cb01a4d..6697eb022c4ecf7d43a79c116105051475e98dd7 100644 --- a/crates/settings_ui/src/pages/tool_permissions_setup.rs +++ b/crates/settings_ui/src/pages/tool_permissions_setup.rs @@ -249,10 +249,13 @@ fn render_tool_list_item( h_flex() .w_full() + .min_w_0() .py_3() .justify_between() .child( v_flex() + .w_full() + .min_w_0() .child(h_flex().gap_1().child(Label::new(tool.name)).when_some( rule_summary, |this, summary| { @@ -1072,9 +1075,12 @@ fn render_global_default_mode_section(current_mode: ToolPermissionMode) -> AnyEl h_flex() .my_4() + .min_w_0() .justify_between() .child( v_flex() + .w_full() + .min_w_0() .child(Label::new("Default Permission")) .child( Label::new( @@ -1125,13 +1131,18 @@ fn render_default_mode_section( let tool_id_owned = tool_id.to_string(); h_flex() + .min_w_0() .justify_between() .child( - v_flex().child(Label::new("Default Action")).child( - Label::new("Action to take when no patterns match.") - .size(LabelSize::Small) - .color(Color::Muted), - ), + v_flex() + .w_full() + .min_w_0() + .child(Label::new("Default Action")) + .child( + Label::new("Action to take when no patterns match.") + .size(LabelSize::Small) + .color(Color::Muted), + ), ) .child( PopoverMenu::new(format!("default-mode-{}", tool_id)) diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 6388dc5a283656e89d805455732a0044cf43e353..1bae8544b1df47786bb3b199319031888432a35f 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -2883,7 +2883,7 @@ impl SettingsWindow { } fn render_sub_page_breadcrumbs(&self) -> impl IntoElement { - h_flex().gap_1().children( + h_flex().min_w_0().gap_1().overflow_x_hidden().children( itertools::intersperse( std::iter::once(self.current_page().title.into()).chain( self.sub_page_stack @@ -3113,9 +3113,11 @@ impl SettingsWindow { if let Some(current_sub_page) = self.sub_page_stack.last() { page_header = h_flex() .w_full() + .min_w_0() .justify_between() .child( h_flex() + .min_w_0() .ml_neg_1p5() .gap_1() .child( @@ -3130,17 +3132,19 @@ impl SettingsWindow { ) .when(current_sub_page.link.in_json, |this| { this.child( - Button::new("open-in-settings-file", "Edit in settings.json") - .tab_index(0_isize) - .style(ButtonStyle::OutlinedGhost) - .tooltip(Tooltip::for_action_title_in( - "Edit in settings.json", - &OpenCurrentFile, - &self.focus_handle, - )) - .on_click(cx.listener(|this, _, window, cx| { - this.open_current_settings_file(window, cx); - })), + div().flex_shrink_0().child( + Button::new("open-in-settings-file", "Edit in settings.json") + .tab_index(0_isize) + .style(ButtonStyle::OutlinedGhost) + .tooltip(Tooltip::for_action_title_in( + "Edit in settings.json", + &OpenCurrentFile, + &self.focus_handle, + )) + .on_click(cx.listener(|this, _, window, cx| { + this.open_current_settings_file(window, cx); + })), + ), ) }) .into_any_element(); @@ -3310,6 +3314,7 @@ impl SettingsWindow { .pt_6() .gap_4() .flex_1() + .min_w_0() .bg(cx.theme().colors().editor_background) .child( v_flex()