Merge branch 'master' into breaking

This commit is contained in:
Evan Almloff 2024-01-16 10:38:55 -06:00
commit d44b0b34c8
9 changed files with 188 additions and 105 deletions

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Clear cache - name: Clear cache
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
github-token: ${{ secrets.cache_controller }} github-token: ${{ secrets.cache_controller }}
script: | script: |

View file

@ -21,9 +21,15 @@ impl Create {
let path = cargo_generate::generate(args)?; let path = cargo_generate::generate(args)?;
post_create(&path)
}
}
// being also used by `init`
pub fn post_create(path: &PathBuf) -> Result<()> {
// first run cargo fmt // first run cargo fmt
let mut cmd = Command::new("cargo"); let mut cmd = Command::new("cargo");
let cmd = cmd.arg("fmt").current_dir(&path); let cmd = cmd.arg("fmt").current_dir(path);
let output = cmd.output().expect("failed to execute process"); let output = cmd.output().expect("failed to execute process");
if !output.status.success() { if !output.status.success() {
log::error!("cargo fmt failed"); log::error!("cargo fmt failed");
@ -62,7 +68,6 @@ impl Create {
Ok(()) Ok(())
} }
}
fn remove_triple_newlines(string: &str) -> String { fn remove_triple_newlines(string: &str) -> String {
let mut new_string = String::new(); let mut new_string = String::new();

View file

@ -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)
}
}

View file

@ -6,6 +6,7 @@ pub mod check;
pub mod clean; pub mod clean;
pub mod config; pub mod config;
pub mod create; pub mod create;
pub mod init;
pub mod plugin; pub mod plugin;
pub mod serve; pub mod serve;
pub mod translate; pub mod translate;
@ -56,9 +57,12 @@ pub enum Commands {
/// Build, watch & serve the Rust WASM app and all of its assets. /// Build, watch & serve the Rust WASM app and all of its assets.
Serve(serve::Serve), Serve(serve::Serve),
/// Init a new project for Dioxus. /// Create a new project for Dioxus.
Create(create::Create), Create(create::Create),
/// Init a new project for Dioxus
Init(init::Init),
/// Clean output artifacts. /// Clean output artifacts.
Clean(clean::Clean), Clean(clean::Clean),
@ -94,6 +98,7 @@ impl Display for Commands {
Commands::Translate(_) => write!(f, "translate"), Commands::Translate(_) => write!(f, "translate"),
Commands::Serve(_) => write!(f, "serve"), Commands::Serve(_) => write!(f, "serve"),
Commands::Create(_) => write!(f, "create"), Commands::Create(_) => write!(f, "create"),
Commands::Init(_) => write!(f, "init"),
Commands::Clean(_) => write!(f, "clean"), Commands::Clean(_) => write!(f, "clean"),
Commands::Config(_) => write!(f, "config"), Commands::Config(_) => write!(f, "config"),
Commands::Version(_) => write!(f, "version"), Commands::Version(_) => write!(f, "version"),

View file

@ -23,16 +23,16 @@ impl Serve {
crate_config.with_release(self.serve.release); crate_config.with_release(self.serve.release);
crate_config.with_verbose(self.serve.verbose); crate_config.with_verbose(self.serve.verbose);
if self.serve.example.is_some() { if let Some(example) = self.serve.example {
crate_config.as_example(self.serve.example.unwrap()); crate_config.as_example(example);
} }
if self.serve.profile.is_some() { if let Some(profile) = self.serve.profile {
crate_config.set_profile(self.serve.profile.unwrap()); crate_config.set_profile(profile);
} }
if self.serve.features.is_some() { if let Some(features) = self.serve.features {
crate_config.set_features(self.serve.features.unwrap()); crate_config.set_features(features);
} }
if let Some(target) = self.serve.target { if let Some(target) = self.serve.target {

View file

@ -25,7 +25,6 @@ pub fn set_up_logging() {
colors_line.get_color(&record.level()).to_fg_str() colors_line.get_color(&record.level()).to_fg_str()
), ),
level = colors_level.color(record.level()), level = colors_level.color(record.level()),
message = message,
)); ));
}) })
.level(match std::env::var("DIOXUS_LOG") { .level(match std::env::var("DIOXUS_LOG") {

View file

@ -43,51 +43,23 @@ async fn main() -> anyhow::Result<()> {
set_up_logging(); 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 { match args.action {
Translate(opts) => opts Translate(opts) => opts
.translate() .translate()
.map_err(|e| anyhow!("🚫 Translation of HTML into RSX failed: {}", e)), .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(opts) => opts
.create() .create()
.map_err(|e| anyhow!("🚫 Creating new project failed: {}", e)), .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(opts) => opts
.config() .config()
.map_err(|e| anyhow!("🚫 Configuring new project failed: {}", e)), .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")] #[cfg(feature = "plugin")]
Plugin(opts) => opts Plugin(opts) => opts
.plugin() .plugin()
@ -110,6 +82,39 @@ async fn main() -> anyhow::Result<()> {
Ok(()) 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!(),
}
}
} }
} }

View file

@ -1,5 +1,6 @@
use crate::file_data::FileEngine; use crate::file_data::FileEngine;
use crate::file_data::HasFileData; use crate::file_data::HasFileData;
use std::ops::Deref;
use std::{collections::HashMap, fmt::Debug}; use std::{collections::HashMap, fmt::Debug};
use dioxus_core::Event; use dioxus_core::Event;
@ -19,6 +20,37 @@ pub enum FormValue {
VecText(Vec<String>), VecText(Vec<String>),
} }
impl From<FormValue> for Vec<String> {
fn from(value: FormValue) -> Self {
match value {
FormValue::Text(s) => vec![s],
FormValue::VecText(vec) => 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] {
match self {
FormValue::Text(s) => std::slice::from_ref(s),
FormValue::VecText(vec) => vec.as_slice(),
}
}
/// Convert into Vec<String>
pub fn to_vec(self) -> Vec<String> {
self.into()
}
}
/* DOMEvent: Send + SyncTarget relatedTarget */ /* DOMEvent: Send + SyncTarget relatedTarget */
pub struct FormData { pub struct FormData {
inner: Box<dyn HasFormData>, inner: Box<dyn HasFormData>,

View file

@ -389,7 +389,25 @@ impl HasFormData for WebFormData {
} }
fn values(&self) -> HashMap<String, FormValue> { fn values(&self) -> HashMap<String, FormValue> {
let mut values = std::collections::HashMap::new(); let mut values = HashMap::new();
fn insert_value(map: &mut HashMap<String, FormValue>, 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 // try to fill in form values
if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() { if let Some(form) = self.element.dyn_ref::<web_sys::HtmlFormElement>() {
@ -398,20 +416,18 @@ impl HasFormData for WebFormData {
if let Ok(array) = value.dyn_into::<Array>() { if let Ok(array) = value.dyn_into::<Array>() {
if let Some(name) = array.get(0).as_string() { if let Some(name) = array.get(0).as_string() {
if let Ok(item_values) = array.get(1).dyn_into::<Array>() { if let Ok(item_values) = array.get(1).dyn_into::<Array>() {
let item_values: Vec<String> = item_values
item_values.iter().filter_map(|v| v.as_string()).collect(); .iter()
.filter_map(|v| v.as_string())
values.insert(name, FormValue::VecText(item_values)); .for_each(|v| insert_value(&mut values, name.clone(), v));
} else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() { } else if let Ok(item_value) = array.get(1).dyn_into::<JsValue>() {
values.insert(name, FormValue::Text(item_value.as_string().unwrap())); insert_value(&mut values, name, item_value.as_string().unwrap());
} }
} }
} }
} }
} } else if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
// try to fill in select element values // try to fill in select element values
if let Some(select) = self.element.dyn_ref::<web_sys::HtmlSelectElement>() {
let options = get_select_data(select); let options = get_select_data(select);
values.insert("options".to_string(), FormValue::VecText(options)); values.insert("options".to_string(), FormValue::VecText(options));
} }
@ -536,19 +552,7 @@ export function get_form_data(form) {
const formData = new FormData(form); const formData = new FormData(form);
for (let name of formData.keys()) { 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)); 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;
}
} }
return values; return values;