From d85e3dea7155e614b50ca42eeac1e3c1fc8cf656 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 12:56:56 +0000 Subject: [PATCH 01/10] Bump actions/github-script from 6 to 7 Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/wipe_cache.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wipe_cache.yml b/.github/workflows/wipe_cache.yml index 2ecced4af..5a78a1e57 100644 --- a/.github/workflows/wipe_cache.yml +++ b/.github/workflows/wipe_cache.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Clear cache - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.cache_controller }} script: | From f833d95e79a1368eece29a53a00c3d8a9d927fbc Mon Sep 17 00:00:00 2001 From: serzhiio Date: Mon, 15 Jan 2024 17:16:44 +0400 Subject: [PATCH 02/10] Added useful methods --- packages/html/src/events/form.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index d22a5219f..4183326ae 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -18,6 +18,27 @@ pub enum FormValue { Text(String), VecText(Vec), } +impl Into> for FormValue { + fn into(self) -> Vec { + match self{ + FormValue::Text(s) => vec![s], + FormValue::VecText(vec) => vec, + } + } +} +impl FormValue { + /// Convenient way to represent Value as slice + pub fn as_slice(&self) -> &[String] { + match self{ + FormValue::Text(s) => std::slice::from_ref(s), + FormValue::VecText(vec) => vec.as_slice(), + } + } + /// Convert into Vec + pub fn to_vec(self) -> Vec { + self.into() + } +} /* DOMEvent: Send + SyncTarget relatedTarget */ pub struct FormData { From c1fbf31a274c89a47c4681f56fff6aacb7789fae Mon Sep 17 00:00:00 2001 From: serzhiio Date: Mon, 15 Jan 2024 17:21:05 +0400 Subject: [PATCH 03/10] Form fields with same name can aggregate in array of values. --- packages/web/src/event.rs | 53 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index 2e9632eae..da242f569 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -389,7 +389,27 @@ impl HasFormData for WebFormData { } fn values(&self) -> HashMap { - let mut values = std::collections::HashMap::new(); + let mut values = HashMap::new(); + + fn insert_value(map: &mut HashMap, key: String, new_value: String) { + match map.entry(key) { + std::collections::hash_map::Entry::Occupied(mut o) => { + let first_value = match o.get_mut() { + FormValue::Text(data) => { + std::mem::take(data) + } + FormValue::VecText(vec) => { + vec.push(new_value); + return + } + }; + let _ = o.insert(FormValue::VecText(vec![first_value, new_value])); + } + std::collections::hash_map::Entry::Vacant(v) => { + let _ = v.insert(FormValue::Text(new_value)); + } + } + }; // try to fill in form values if let Some(form) = self.element.dyn_ref::() { @@ -398,24 +418,19 @@ impl HasFormData for WebFormData { if let Ok(array) = value.dyn_into::() { if let Some(name) = array.get(0).as_string() { if let Ok(item_values) = array.get(1).dyn_into::() { - let item_values: Vec = - item_values.iter().filter_map(|v| v.as_string()).collect(); - - values.insert(name, FormValue::VecText(item_values)); + item_values.iter() + .filter_map(|v| v.as_string()) + .for_each(|v| { + insert_value(&mut values, name.clone(), v) + }); } else if let Ok(item_value) = array.get(1).dyn_into::() { - values.insert(name, FormValue::Text(item_value.as_string().unwrap())); + insert_value(&mut values, name, item_value.as_string().unwrap()); } } } } } - // try to fill in select element values - if let Some(select) = self.element.dyn_ref::() { - let options = get_select_data(select); - values.insert("options".to_string(), FormValue::VecText(options)); - } - values } @@ -536,19 +551,7 @@ export function get_form_data(form) { const formData = new FormData(form); for (let name of formData.keys()) { - const fieldType = form.elements[name].type; - console.log(fieldType); - - switch (fieldType) { - case "select-multiple": - values.set(name, formData.getAll(name)); - break; - - // add cases for fieldTypes that can hold multiple values here - default: - values.set(name, formData.get(name)); - break; - } + values.set(name, formData.getAll(name)); } return values; From a92d1a9424a858047350e41943725707a6060ff5 Mon Sep 17 00:00:00 2001 From: serzhiio Date: Mon, 15 Jan 2024 17:28:00 +0400 Subject: [PATCH 04/10] rustfmt --- packages/html/src/events/form.rs | 4 ++-- packages/web/src/event.rs | 13 +++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 4183326ae..5ccd525dc 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -20,7 +20,7 @@ pub enum FormValue { } impl Into> for FormValue { fn into(self) -> Vec { - match self{ + match self { FormValue::Text(s) => vec![s], FormValue::VecText(vec) => vec, } @@ -29,7 +29,7 @@ impl Into> for FormValue { impl FormValue { /// Convenient way to represent Value as slice pub fn as_slice(&self) -> &[String] { - match self{ + match self { FormValue::Text(s) => std::slice::from_ref(s), FormValue::VecText(vec) => vec.as_slice(), } diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index da242f569..066c380f4 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -395,12 +395,10 @@ impl HasFormData for WebFormData { match map.entry(key) { std::collections::hash_map::Entry::Occupied(mut o) => { let first_value = match o.get_mut() { - FormValue::Text(data) => { - std::mem::take(data) - } + FormValue::Text(data) => std::mem::take(data), FormValue::VecText(vec) => { vec.push(new_value); - return + return; } }; let _ = o.insert(FormValue::VecText(vec![first_value, new_value])); @@ -418,11 +416,10 @@ impl HasFormData for WebFormData { if let Ok(array) = value.dyn_into::() { if let Some(name) = array.get(0).as_string() { if let Ok(item_values) = array.get(1).dyn_into::() { - item_values.iter() + item_values + .iter() .filter_map(|v| v.as_string()) - .for_each(|v| { - insert_value(&mut values, name.clone(), v) - }); + .for_each(|v| insert_value(&mut values, name.clone(), v)); } else if let Ok(item_value) = array.get(1).dyn_into::() { insert_value(&mut values, name, item_value.as_string().unwrap()); } From 00cd0dae6ef28c6d1eeaae059ccf719e1f29fda0 Mon Sep 17 00:00:00 2001 From: serzhiio Date: Mon, 15 Jan 2024 17:38:31 +0400 Subject: [PATCH 05/10] From impl --- packages/html/src/events/form.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 5ccd525dc..249d17c79 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -18,9 +18,9 @@ pub enum FormValue { Text(String), VecText(Vec), } -impl Into> for FormValue { - fn into(self) -> Vec { - match self { +impl From for Vec { + fn from(value: FormValue) -> Self { + match value { FormValue::Text(s) => vec![s], FormValue::VecText(vec) => vec, } From da308b4cddea524c4a6bdd8e26345f8eb8293445 Mon Sep 17 00:00:00 2001 From: serzhiio Date: Mon, 15 Jan 2024 17:42:03 +0400 Subject: [PATCH 06/10] typo --- packages/web/src/event.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index 066c380f4..0f745cc4a 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -407,7 +407,7 @@ impl HasFormData for WebFormData { let _ = v.insert(FormValue::Text(new_value)); } } - }; + } // try to fill in form values if let Some(form) = self.element.dyn_ref::() { From 1db8bd7eddb8ac2027141774debb36df8ce3bafd Mon Sep 17 00:00:00 2001 From: hem1t <31543841+hem1t@users.noreply.github.com> Date: Tue, 16 Jan 2024 18:51:01 +0530 Subject: [PATCH 07/10] Minor fixes in cli (#1837) * not using bin, until needed also removes an unnecessary warning! * removed redundant line maybe, it was readability? * using same `if let` pattern as below * to `get_bin(args.bin)?` with `Ok(())` at last * unreachable! --- packages/cli/src/cli/serve.rs | 12 +++---- packages/cli/src/logging.rs | 1 - packages/cli/src/main.rs | 67 ++++++++++++++++++----------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index b4362729f..5a483ec54 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -23,16 +23,16 @@ impl Serve { crate_config.with_release(self.serve.release); crate_config.with_verbose(self.serve.verbose); - if self.serve.example.is_some() { - crate_config.as_example(self.serve.example.unwrap()); + if let Some(example) = self.serve.example { + crate_config.as_example(example); } - if self.serve.profile.is_some() { - crate_config.set_profile(self.serve.profile.unwrap()); + if let Some(profile) = self.serve.profile { + crate_config.set_profile(profile); } - if self.serve.features.is_some() { - crate_config.set_features(self.serve.features.unwrap()); + if let Some(features) = self.serve.features { + crate_config.set_features(features); } if let Some(target) = self.serve.target { diff --git a/packages/cli/src/logging.rs b/packages/cli/src/logging.rs index 31d088737..0d902f86f 100644 --- a/packages/cli/src/logging.rs +++ b/packages/cli/src/logging.rs @@ -25,7 +25,6 @@ pub fn set_up_logging() { colors_line.get_color(&record.level()).to_fg_str() ), level = colors_level.color(record.level()), - message = message, )); }) .level(match std::env::var("DIOXUS_LOG") { diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index a603f7929..c1ebfbb4c 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -43,39 +43,11 @@ async fn main() -> anyhow::Result<()> { set_up_logging(); - let bin = get_bin(args.bin); - - if let Ok(bin) = &bin { - let _dioxus_config = DioxusConfig::load(Some(bin.clone())) - .map_err(|e| anyhow!("Failed to load Dioxus config because: {e}"))? - .unwrap_or_else(|| { - log::info!("You appear to be creating a Dioxus project from scratch; we will use the default config"); - DioxusConfig::default() - }); - - #[cfg(feature = "plugin")] - PluginManager::init(_dioxus_config.plugin) - .map_err(|e| anyhow!("🚫 Plugin system initialization failed: {e}"))?; - } - match args.action { Translate(opts) => opts .translate() .map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)), - Build(opts) if bin.is_ok() => opts - .build(Some(bin.unwrap().clone()), None) - .map_err(|e| anyhow!("🚫 Building project failed: {}", e)), - - Clean(opts) if bin.is_ok() => opts - .clean(Some(bin.unwrap().clone())) - .map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)), - - Serve(opts) if bin.is_ok() => opts - .serve(Some(bin.unwrap().clone())) - .await - .map_err(|e| anyhow!("🚫 Serving project failed: {}", e)), - Create(opts) => opts .create() .map_err(|e| anyhow!("🚫 Creating new project failed: {}", e)), @@ -84,10 +56,6 @@ async fn main() -> anyhow::Result<()> { .config() .map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)), - Bundle(opts) if bin.is_ok() => opts - .bundle(Some(bin.unwrap().clone())) - .map_err(|e| anyhow!("🚫 Bundling project failed: {}", e)), - #[cfg(feature = "plugin")] Plugin(opts) => opts .plugin() @@ -110,6 +78,39 @@ async fn main() -> anyhow::Result<()> { Ok(()) } - _ => Err(anyhow::anyhow!(bin.unwrap_err())), + action => { + let bin = get_bin(args.bin)?; + let _dioxus_config = DioxusConfig::load(Some(bin.clone())) + .map_err(|e| anyhow!("Failed to load Dioxus config because: {e}"))? + .unwrap_or_else(|| { + log::info!("You appear to be creating a Dioxus project from scratch; we will use the default config"); + DioxusConfig::default() + }); + + #[cfg(feature = "plugin")] + PluginManager::init(_dioxus_config.plugin) + .map_err(|e| anyhow!("🚫 Plugin system initialization failed: {e}"))?; + + match action { + Build(opts) => opts + .build(Some(bin.clone()), None) + .map_err(|e| anyhow!("🚫 Building project failed: {}", e)), + + Clean(opts) => opts + .clean(Some(bin.clone())) + .map_err(|e| anyhow!("🚫 Cleaning project failed: {}", e)), + + Serve(opts) => opts + .serve(Some(bin.clone())) + .await + .map_err(|e| anyhow!("🚫 Serving project failed: {}", e)), + + Bundle(opts) => opts + .bundle(Some(bin.clone())) + .map_err(|e| anyhow!("🚫 Bundling project failed: {}", e)), + + _ => unreachable!(), + } + } } } From 6bc2fb0906115e0cbb578905aea68c63c36fc122 Mon Sep 17 00:00:00 2001 From: serzhiio Date: Tue, 16 Jan 2024 18:17:53 +0400 Subject: [PATCH 08/10] fix MultipleSelect --- packages/web/src/event.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index 0f745cc4a..e79b55fe8 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -426,6 +426,10 @@ impl HasFormData for WebFormData { } } } + } else if let Some(select) = self.element.dyn_ref::() { + // try to fill in select element values + let options = get_select_data(select); + values.insert("options".to_string(), FormValue::VecText(options)); } values From c6e1b0f72808325ab311869e26cf315f7205da5f Mon Sep 17 00:00:00 2001 From: hem1t <31543841+hem1t@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:55:07 +0530 Subject: [PATCH 09/10] `init` subcommand (#1840) * `init` subcommand * clippy --- packages/cli/src/cli/create.rs | 85 ++++++++++++++++++---------------- packages/cli/src/cli/init.rs | 33 +++++++++++++ packages/cli/src/cli/mod.rs | 7 ++- packages/cli/src/main.rs | 4 ++ 4 files changed, 88 insertions(+), 41 deletions(-) create mode 100644 packages/cli/src/cli/init.rs diff --git a/packages/cli/src/cli/create.rs b/packages/cli/src/cli/create.rs index 92b0334f5..73eda7d0b 100644 --- a/packages/cli/src/cli/create.rs +++ b/packages/cli/src/cli/create.rs @@ -21,49 +21,54 @@ impl Create { let path = cargo_generate::generate(args)?; - // first run cargo fmt - let mut cmd = Command::new("cargo"); - let cmd = cmd.arg("fmt").current_dir(&path); - let output = cmd.output().expect("failed to execute process"); - if !output.status.success() { - log::error!("cargo fmt failed"); - log::error!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - log::error!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - } - - // then format the toml - let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")]; - for toml_path in &toml_paths { - let toml = std::fs::read_to_string(toml_path)?; - let mut toml = toml.parse::().map_err(|e| { - anyhow::anyhow!( - "failed to parse toml at {}: {}", - toml_path.display(), - e.to_string() - ) - })?; - - toml.as_table_mut().fmt(); - - let as_string = toml.to_string(); - let new_string = remove_triple_newlines(&as_string); - let mut file = std::fs::File::create(toml_path)?; - file.write_all(new_string.as_bytes())?; - } - - // remove any triple newlines from the readme - let readme_path = path.join("README.md"); - let readme = std::fs::read_to_string(&readme_path)?; - let new_readme = remove_triple_newlines(&readme); - let mut file = std::fs::File::create(readme_path)?; - file.write_all(new_readme.as_bytes())?; - - log::info!("Generated project at {}", path.display()); - - Ok(()) + post_create(&path) } } +// being also used by `init` +pub fn post_create(path: &PathBuf) -> Result<()> { + // first run cargo fmt + let mut cmd = Command::new("cargo"); + let cmd = cmd.arg("fmt").current_dir(path); + let output = cmd.output().expect("failed to execute process"); + if !output.status.success() { + log::error!("cargo fmt failed"); + log::error!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + log::error!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + } + + // then format the toml + let toml_paths = [path.join("Cargo.toml"), path.join("Dioxus.toml")]; + for toml_path in &toml_paths { + let toml = std::fs::read_to_string(toml_path)?; + let mut toml = toml.parse::().map_err(|e| { + anyhow::anyhow!( + "failed to parse toml at {}: {}", + toml_path.display(), + e.to_string() + ) + })?; + + toml.as_table_mut().fmt(); + + let as_string = toml.to_string(); + let new_string = remove_triple_newlines(&as_string); + let mut file = std::fs::File::create(toml_path)?; + file.write_all(new_string.as_bytes())?; + } + + // remove any triple newlines from the readme + let readme_path = path.join("README.md"); + let readme = std::fs::read_to_string(&readme_path)?; + let new_readme = remove_triple_newlines(&readme); + let mut file = std::fs::File::create(readme_path)?; + file.write_all(new_readme.as_bytes())?; + + log::info!("Generated project at {}", path.display()); + + Ok(()) +} + fn remove_triple_newlines(string: &str) -> String { let mut new_string = String::new(); for char in string.chars() { diff --git a/packages/cli/src/cli/init.rs b/packages/cli/src/cli/init.rs new file mode 100644 index 000000000..1ac0602c3 --- /dev/null +++ b/packages/cli/src/cli/init.rs @@ -0,0 +1,33 @@ +use super::*; +use cargo_generate::{GenerateArgs, TemplatePath}; + +#[derive(Clone, Debug, Default, Deserialize, Parser)] +#[clap(name = "init")] +pub struct Init { + /// Template path + #[clap(default_value = "gh:dioxuslabs/dioxus-template", long)] + template: String, +} + +impl Init { + pub fn init(self) -> Result<()> { + // get dir name + let name = std::env::current_dir()? + .file_name() + .map(|f| f.to_str().unwrap().to_string()); + + let args = GenerateArgs { + template_path: TemplatePath { + auto_path: Some(self.template), + ..Default::default() + }, + name, + init: true, + ..Default::default() + }; + + let path = cargo_generate::generate(args)?; + + create::post_create(&path) + } +} diff --git a/packages/cli/src/cli/mod.rs b/packages/cli/src/cli/mod.rs index 4295bfa9b..21d1b63c6 100644 --- a/packages/cli/src/cli/mod.rs +++ b/packages/cli/src/cli/mod.rs @@ -6,6 +6,7 @@ pub mod check; pub mod clean; pub mod config; pub mod create; +pub mod init; pub mod plugin; pub mod serve; pub mod translate; @@ -56,9 +57,12 @@ pub enum Commands { /// Build, watch & serve the Rust WASM app and all of its assets. Serve(serve::Serve), - /// Init a new project for Dioxus. + /// Create a new project for Dioxus. Create(create::Create), + /// Init a new project for Dioxus + Init(init::Init), + /// Clean output artifacts. Clean(clean::Clean), @@ -94,6 +98,7 @@ impl Display for Commands { Commands::Translate(_) => write!(f, "translate"), Commands::Serve(_) => write!(f, "serve"), Commands::Create(_) => write!(f, "create"), + Commands::Init(_) => write!(f, "init"), Commands::Clean(_) => write!(f, "clean"), Commands::Config(_) => write!(f, "config"), Commands::Version(_) => write!(f, "version"), diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index c1ebfbb4c..4114d629a 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -52,6 +52,10 @@ async fn main() -> anyhow::Result<()> { .create() .map_err(|e| anyhow!("🚫 Creating new project failed: {}", e)), + Init(opts) => opts + .init() + .map_err(|e| anyhow!("🚫 Initialising a new project failed: {}", e)), + Config(opts) => opts .config() .map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)), From a20a85dad6713574527dd4fe33fdbde8ecea8c25 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 16 Jan 2024 10:30:59 -0600 Subject: [PATCH 10/10] implement deref for FormValue --- packages/html/src/events/form.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/html/src/events/form.rs b/packages/html/src/events/form.rs index 249d17c79..75cc51978 100644 --- a/packages/html/src/events/form.rs +++ b/packages/html/src/events/form.rs @@ -1,5 +1,6 @@ use crate::file_data::FileEngine; use crate::file_data::HasFileData; +use std::ops::Deref; use std::{collections::HashMap, fmt::Debug}; use dioxus_core::Event; @@ -18,6 +19,7 @@ pub enum FormValue { Text(String), VecText(Vec), } + impl From for Vec { fn from(value: FormValue) -> Self { match value { @@ -26,6 +28,15 @@ impl From for Vec { } } } + +impl Deref for FormValue { + type Target = [String]; + + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + impl FormValue { /// Convenient way to represent Value as slice pub fn as_slice(&self) -> &[String] {