mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 04:33:06 +00:00
Merge branch 'master' into breaking
This commit is contained in:
commit
d44b0b34c8
9 changed files with 188 additions and 105 deletions
2
.github/workflows/wipe_cache.yml
vendored
2
.github/workflows/wipe_cache.yml
vendored
|
@ -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: |
|
||||||
|
|
|
@ -21,49 +21,54 @@ impl Create {
|
||||||
|
|
||||||
let path = cargo_generate::generate(args)?;
|
let path = cargo_generate::generate(args)?;
|
||||||
|
|
||||||
// first run cargo fmt
|
post_create(&path)
|
||||||
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::<toml_edit::Document>().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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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::<toml_edit::Document>().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 {
|
fn remove_triple_newlines(string: &str) -> String {
|
||||||
let mut new_string = String::new();
|
let mut new_string = String::new();
|
||||||
for char in string.chars() {
|
for char in string.chars() {
|
||||||
|
|
33
packages/cli/src/cli/init.rs
Normal file
33
packages/cli/src/cli/init.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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") {
|
||||||
|
|
|
@ -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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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;
|
values.set(name, formData.getAll(name));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return values;
|
return values;
|
||||||
|
|
Loading…
Reference in a new issue