settings_ui: Add proxy edit box (#45684)

Xiaobo Liu created

Release Notes:

- settings_ui: Added a field to configure the network proxy.

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>

Change summary

assets/settings/default.json        |  2 +-
crates/client/src/client.rs         | 24 ++++++++++++++++++++++--
crates/remote_server/src/unix.rs    |  6 ++++--
crates/settings_ui/src/page_data.rs | 18 +++++++-----------
4 files changed, 34 insertions(+), 16 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -2235,7 +2235,7 @@
   // Examples:
   //   - "proxy": "socks5h://localhost:10808"
   //   - "proxy": "http://127.0.0.1:10809"
-  "proxy": null,
+  "proxy": "",
   // Set to configure aliases for the command palette.
   // When typing a query which is a key of this object, the value will be used instead.
   //

crates/client/src/client.rs 🔗

@@ -121,7 +121,9 @@ pub struct ProxySettings {
 impl ProxySettings {
     pub fn proxy_url(&self) -> Option<Url> {
         self.proxy
-            .as_ref()
+            .as_deref()
+            .map(str::trim)
+            .filter(|input| !input.is_empty())
             .and_then(|input| {
                 input
                     .parse::<Url>()
@@ -135,7 +137,12 @@ impl ProxySettings {
 impl Settings for ProxySettings {
     fn from_settings(content: &settings::SettingsContent) -> Self {
         Self {
-            proxy: content.proxy.clone(),
+            proxy: content
+                .proxy
+                .as_deref()
+                .map(str::trim)
+                .filter(|proxy| !proxy.is_empty())
+                .map(ToOwned::to_owned),
         }
     }
 }
@@ -1801,6 +1808,19 @@ mod tests {
     use settings::SettingsStore;
     use std::future;
 
+    #[test]
+    fn test_proxy_settings_trims_and_ignores_empty_proxy() {
+        let mut content = SettingsContent::default();
+        content.proxy = Some("   ".to_owned());
+        assert_eq!(ProxySettings::from_settings(&content).proxy, None);
+
+        content.proxy = Some("http://127.0.0.1:10809".to_owned());
+        assert_eq!(
+            ProxySettings::from_settings(&content).proxy.as_deref(),
+            Some("http://127.0.0.1:10809")
+        );
+    }
+
     #[gpui::test(iterations = 10)]
     async fn test_reconnection(cx: &mut TestAppContext) {
         init_test(cx);

crates/remote_server/src/unix.rs 🔗

@@ -953,8 +953,10 @@ fn read_proxy_settings(cx: &mut Context<HeadlessProject>) -> Option<Url> {
     let proxy_str = ProxySettings::get_global(cx).proxy.to_owned();
 
     proxy_str
-        .as_ref()
-        .and_then(|input: &String| {
+        .as_deref()
+        .map(str::trim)
+        .filter(|input| !input.is_empty())
+        .and_then(|input| {
             input
                 .parse::<Url>()
                 .inspect_err(|e| log::error!("Error parsing proxy settings: {}", e))

crates/settings_ui/src/page_data.rs 🔗

@@ -6236,20 +6236,16 @@ pub(crate) fn settings_data(cx: &App) -> Vec<SettingsPage> {
             title: "Network",
             items: vec![
                 SettingsPageItem::SectionHeader("Network"),
-                // todo(settings_ui): Proxy needs a default
                 SettingsPageItem::SettingItem(SettingItem {
                     title: "Proxy",
                     description: "The proxy to use for network requests.",
-                    field: Box::new(
-                        SettingField {
-                            json_path: Some("proxy"),
-                            pick: |settings_content| settings_content.proxy.as_ref(),
-                            write: |settings_content, value| {
-                                settings_content.proxy = value;
-                            },
-                        }
-                        .unimplemented(),
-                    ),
+                    field: Box::new(SettingField {
+                        json_path: Some("proxy"),
+                        pick: |settings_content| settings_content.proxy.as_ref(),
+                        write: |settings_content, value| {
+                            settings_content.proxy = value;
+                        },
+                    }),
                     metadata: Some(Box::new(SettingsFieldMetadata {
                         placeholder: Some("socks5h://localhost:10808"),
                         ..Default::default()