diff --git a/Cargo.lock b/Cargo.lock index 253a54d..c520522 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,6 +158,7 @@ dependencies = [ "thiserror", "tokio", "toml", + "url 2.5.2", ] [[package]] @@ -894,7 +895,7 @@ dependencies = [ "sluice", "tracing", "tracing-futures", - "url 2.5.0", + "url 2.5.2", "waker-fn", ] @@ -1881,9 +1882,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index a00bf1e..6c4a51a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,4 @@ srtemplate = { version = "0.3.0", features = [] } thiserror = "1.0.60" tokio = { version = "1.37.0", features = ["sync"] } toml = "0.8.12" +url = "2.5.2" diff --git a/data/ui/endpoint_pane.blp b/data/ui/endpoint_pane.blp index a5b58e4..c7ff01d 100644 --- a/data/ui/endpoint_pane.blp +++ b/data/ui/endpoint_pane.blp @@ -98,6 +98,27 @@ template $CarteroEndpointPane: Adw.BreakpointBin { Notebook { show-border: false; + NotebookPage { + tab: Label { + label: _("Parameters"); + }; + + child: ScrolledWindow { + hexpand: true; + vexpand: true; + + Adw.Clamp { + styles [ + "background" + ] + + maximum-size: 720; + + $CarteroKeyValuePane parameter_pane {} + } + }; + } + NotebookPage { tab: Label { label: _("Headers"); diff --git a/po/cartero.pot b/po/cartero.pot index 3a78854..e1f3748 100644 --- a/po/cartero.pot +++ b/po/cartero.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: cartero\n" "Report-Msgid-Bugs-To: https://github.com/danirod/cartero/issues\n" -"POT-Creation-Date: 2024-07-26 09:25+0200\n" +"POT-Creation-Date: 2024-07-26 21:32+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -90,15 +90,19 @@ msgstr "" msgid "Execute this HTTP request" msgstr "" -#: data/ui/endpoint_pane.blp:103 data/ui/response_panel.blp:47 +#: data/ui/endpoint_pane.blp:103 +msgid "Parameters" +msgstr "" + +#: data/ui/endpoint_pane.blp:124 data/ui/response_panel.blp:47 msgid "Headers" msgstr "" -#: data/ui/endpoint_pane.blp:124 +#: data/ui/endpoint_pane.blp:145 msgid "Variables" msgstr "" -#: data/ui/endpoint_pane.blp:145 data/ui/response_panel.blp:68 +#: data/ui/endpoint_pane.blp:166 data/ui/response_panel.blp:68 msgid "Body" msgstr "" diff --git a/po/en.po b/po/en.po index 843c5a4..75b54da 100644 --- a/po/en.po +++ b/po/en.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: cartero\n" "Report-Msgid-Bugs-To: https://github.com/danirod/cartero/issues\n" -"POT-Creation-Date: 2024-07-26 09:25+0200\n" +"POT-Creation-Date: 2024-07-26 21:32+0200\n" "PO-Revision-Date: 2024-06-22 13:31+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -91,15 +91,19 @@ msgstr "" msgid "Execute this HTTP request" msgstr "" -#: data/ui/endpoint_pane.blp:103 data/ui/response_panel.blp:47 +#: data/ui/endpoint_pane.blp:103 +msgid "Parameters" +msgstr "" + +#: data/ui/endpoint_pane.blp:124 data/ui/response_panel.blp:47 msgid "Headers" msgstr "" -#: data/ui/endpoint_pane.blp:124 +#: data/ui/endpoint_pane.blp:145 msgid "Variables" msgstr "" -#: data/ui/endpoint_pane.blp:145 data/ui/response_panel.blp:68 +#: data/ui/endpoint_pane.blp:166 data/ui/response_panel.blp:68 msgid "Body" msgstr "" diff --git a/po/eo.po b/po/eo.po index 58b43ae..9e40db9 100644 --- a/po/eo.po +++ b/po/eo.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: cartero\n" "Report-Msgid-Bugs-To: https://github.com/danirod/cartero/issues\n" -"POT-Creation-Date: 2024-07-26 09:25+0200\n" +"POT-Creation-Date: 2024-07-26 21:32+0200\n" "PO-Revision-Date: 2024-07-25 22:08+0200\n" "Last-Translator: <>\n" "Language-Team: Spanish\n" @@ -89,15 +89,19 @@ msgstr "Petu" msgid "Execute this HTTP request" msgstr "Sendu ĉi tiun http-peton" -#: data/ui/endpoint_pane.blp:103 data/ui/response_panel.blp:47 +#: data/ui/endpoint_pane.blp:103 +msgid "Parameters" +msgstr "" + +#: data/ui/endpoint_pane.blp:124 data/ui/response_panel.blp:47 msgid "Headers" msgstr "Kapoj" -#: data/ui/endpoint_pane.blp:124 +#: data/ui/endpoint_pane.blp:145 msgid "Variables" msgstr "Variabloj" -#: data/ui/endpoint_pane.blp:145 data/ui/response_panel.blp:68 +#: data/ui/endpoint_pane.blp:166 data/ui/response_panel.blp:68 msgid "Body" msgstr "Korpo" diff --git a/po/es.po b/po/es.po index 3e67e90..5fd5d1f 100644 --- a/po/es.po +++ b/po/es.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: cartero\n" "Report-Msgid-Bugs-To: https://github.com/danirod/cartero/issues\n" -"POT-Creation-Date: 2024-07-26 09:25+0200\n" -"PO-Revision-Date: 2024-07-26 01:40+0200\n" +"POT-Creation-Date: 2024-07-26 21:32+0200\n" +"PO-Revision-Date: 2024-07-26 21:32+0200\n" "Last-Translator: <>\n" "Language-Team: Spanish\n" "Language: es\n" @@ -89,15 +89,19 @@ msgstr "Enviar" msgid "Execute this HTTP request" msgstr "Ejecutar esta petición HTTP" -#: data/ui/endpoint_pane.blp:103 data/ui/response_panel.blp:47 +#: data/ui/endpoint_pane.blp:103 +msgid "Parameters" +msgstr "Parámetros" + +#: data/ui/endpoint_pane.blp:124 data/ui/response_panel.blp:47 msgid "Headers" msgstr "Cabeceras" -#: data/ui/endpoint_pane.blp:124 +#: data/ui/endpoint_pane.blp:145 msgid "Variables" msgstr "Variables" -#: data/ui/endpoint_pane.blp:145 data/ui/response_panel.blp:68 +#: data/ui/endpoint_pane.blp:166 data/ui/response_panel.blp:68 msgid "Body" msgstr "Cuerpo" diff --git a/src/widgets/endpoint_pane.rs b/src/widgets/endpoint_pane.rs index e32592c..ed0a4b7 100644 --- a/src/widgets/endpoint_pane.rs +++ b/src/widgets/endpoint_pane.rs @@ -22,6 +22,7 @@ use crate::{entities::EndpointData, error::CarteroError}; mod imp { use std::cell::RefCell; + use std::sync::{Arc, Mutex}; use std::time::Instant; use adw::subclass::breakpoint_bin::BreakpointBinImpl; @@ -30,6 +31,7 @@ mod imp { use gtk::subclass::prelude::*; use gtk::{prelude::*, CompositeTemplate}; use isahc::RequestExt; + use url::Url; use crate::app::CarteroApplication; use crate::client::{BoundRequest, RequestError}; @@ -45,6 +47,9 @@ mod imp { #[template_child(id = "send")] pub send_button: TemplateChild, + #[template_child] + pub parameter_pane: TemplateChild, + #[template_child] pub header_pane: TemplateChild, @@ -68,6 +73,8 @@ mod imp { #[property(get, set, nullable)] pub item_pane: RefCell>, + + variable_changing: Arc>, } #[glib::object_subclass] @@ -95,6 +102,33 @@ mod imp { self.init_settings(); self.variable_pane.assert_always_placeholder(); self.header_pane.assert_always_placeholder(); + self.parameter_pane.assert_always_placeholder(); + + let url_arc = self.variable_changing.clone(); + self.request_url + .connect_changed(glib::clone!(@weak self as window => move |_| { + // It is important to allow the redundant pattern matching because + // is_ok() does not capture the mutex and will cause sync issues. + #[allow(clippy::redundant_pattern_matching)] + if let Ok(_) = url_arc.try_lock() { + if let Err(err) = window.update_query_params() { + println!("{err}"); + } + } + })); + + let parameter_arc = self.variable_changing.clone(); + self.parameter_pane + .connect_changed(glib::clone!(@weak self as window => move |_| { + // It is important to allow the redundant pattern matching because + // is_ok() does not capture the mutex and will cause sync issues. + #[allow(clippy::redundant_pattern_matching)] + if let Ok(_) = parameter_arc.try_lock() { + if let Err(err) = window.update_url_from_query_params() { + println!("{err}"); + } + } + })); } } @@ -104,6 +138,46 @@ mod imp { #[gtk::template_callbacks] impl EndpointPane { + fn update_url_from_query_params(&self) -> Result<(), url::ParseError> { + let table = self.parameter_pane.get_entries(); + + let parsed_url = self.request_url.text().to_string(); + let mut url = Url::parse(&parsed_url)?; + { + let mut pairs = url.query_pairs_mut(); + pairs.clear(); + for item in table { + if item.active() { + let key = item.header_name(); + let value = item.header_value(); + pairs.append_pair(&key, &value); + } + } + } + self.request_url.set_text(url.as_str()); + Ok(()) + } + + fn update_query_params(&self) -> Result<(), url::ParseError> { + let parsed_url = self.request_url.text().to_string(); + let url = Url::parse(&parsed_url)?; + let pairs = url.query_pairs(); + + let entries: Vec = pairs + .map(|(key, value)| { + let key = String::from(key); + let value = String::from(value); + let entry = KeyValue::from((key, value)); + let value = KeyValueItem::from(entry); + value.set_active(true); + value.set_secret(false); + value + }) + .collect(); + self.parameter_pane.set_entries(&entries); + Ok(()) + } + fn mark_dirty(&self) { if let Some(item_pane) = self.obj().item_pane() { item_pane.set_dirty(true); diff --git a/src/widgets/key_value_pane.rs b/src/widgets/key_value_pane.rs index 38f2564..05cbee7 100644 --- a/src/widgets/key_value_pane.rs +++ b/src/widgets/key_value_pane.rs @@ -216,10 +216,7 @@ impl KeyValuePane { pub fn get_entries(&self) -> Vec { let model = &self.model(); let iter = model.iter::(); - iter.filter(|value| value.is_ok()) - .flatten() - .filter(|value| !value.header_name().is_empty() && !value.header_value().is_empty()) - .collect() + iter.filter(|value| value.is_ok()).flatten().collect() } pub fn set_entries(&self, entries: &[KeyValueItem]) {