Skip to content

Commit

Permalink
Merge pull request #125 from miaomiaowu0428/zli-serve
Browse files Browse the repository at this point in the history
Add features to zli
  • Loading branch information
photino authored Aug 11, 2024
2 parents dab306e + a6951cc commit 5f46b18
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 34 deletions.
97 changes: 69 additions & 28 deletions zino-cli/public/zino-config.html
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@
margin-left: 19.1%;
}


.hidden {
display: none;
}
</style>
</head>
<body>
Expand Down Expand Up @@ -236,11 +238,10 @@ <h1 id="project_name">current project: None</h1>
<div class="config-form" id="core-config-form">
<div class="form-description">Core config</div>
<form class="config-details">
<div class="closet">
<div class="option-title">Database</div>
<div class="closet hidden" id="orm-form">
<div class="option-title" >Database</div>

<div class="option-group exclusive">
<div class="unchecked" data-feature="orm">Sqlx</div>
<div class="unchecked" data-feature="orm-mysql">MySQL</div>
<div class="unchecked" data-feature="orm-postgresql">PostgreSQL</div>
<div class="unchecked" data-feature="orm-sqlite">SQLite</div>
Expand Down Expand Up @@ -376,6 +377,7 @@ <h1 id="project_name">current project: None</h1>
}

await fetchCargoToml()
await fetchFeatures()
});

// ask the server to change the current directory
Expand Down Expand Up @@ -413,18 +415,26 @@ <h1 id="project_name">current project: None</h1>


// init the options of each group
function init_options() {
const optionsDivs = document.querySelectorAll('.option-group');

optionsDivs.forEach(div => {
if (div.classList.contains('exclusive')) {
const firstUnchecked = div.querySelector('.unchecked');

if (firstUnchecked) {
firstUnchecked.classList.replace('unchecked', 'checked')
}
async function fetchFeatures() {
try {
const response = fetch('/get_current_features');
let features = await (await response).json();
document.querySelectorAll('.checked').forEach(option => {
option.classList.replace('checked', 'unchecked')
})
for (let feature of features.data.zino_feature) {
Array.from(document.querySelectorAll('#zino-config-form [data-feature]')).filter(option => option.getAttribute('data-feature') === feature).forEach(option => {
option.click()
})
}
});
for (let feature of features.data.core_feature) {
Array.from(document.querySelectorAll('#core-config-form [data-feate]')).filter(option => option.getAttribute('data-feature') === feature).forEach(option => {
option.click()
})
}
} catch (error) {
console.error('Failed to init options:', error);
}
}

function checkedOptions() {
Expand Down Expand Up @@ -470,23 +480,23 @@ <h1 id="project_name">current project: None</h1>
document.querySelector('#aimCargoTomlTextArea').value = (await res.json()).data;
}


function change_option_state() {
this.classList.toggle('unchecked');
this.classList.toggle('checked');
let self_checked = this.classList.contains('checked');

let group = this.parentElement;

if (group.classList.contains('exclusive')) {
group.querySelectorAll('.checked').forEach(option => {
[...group.querySelectorAll('.checked')].filter(o => o !== this).forEach(option => {
option.classList.toggle('checked')
option.classList.toggle('unchecked')
})
}

this.classList.toggle('unchecked');
this.classList.toggle('checked');

let state = this.classList.contains('checked')


if (this.classList.contains('all-options')) {
if (state) {
if (self_checked) {
group.querySelectorAll('.unchecked').forEach(option => {
option.classList.replace('unchecked', 'checked')
})
Expand All @@ -496,7 +506,7 @@ <h1 id="project_name">current project: None</h1>
})
}
} else {
if (state) {
if (self_checked) {
if (group.querySelectorAll('.unchecked').length === 1) {
group.querySelectorAll('.all-options').forEach(option => {
option.classList.replace('unchecked', 'checked')
Expand All @@ -509,6 +519,17 @@ <h1 id="project_name">current project: None</h1>
}
}

const ormOption = document.querySelector('#zino-config-form [data-feature="orm"]');
const ormForm = document.getElementById('orm-form');
if (ormOption && ormOption.classList.contains('checked')) {
ormForm.classList.remove('hidden');
} else {
ormForm.classList.add('hidden');
ormForm.querySelectorAll('.option-group div').forEach(option => {
option.classList.replace('checked', 'unchecked');
});
}

generateCargoToml();
}

Expand Down Expand Up @@ -537,10 +558,30 @@ <h1 id="project_name">current project: None</h1>
});
});

window.onload = () => {
fetchCurrentDir();
fetchCargoToml();
init_options();
// save the generated Cargo.toml
document.getElementById('save-config').addEventListener('click', async () => {
const aimCargoToml = document.getElementById('aimCargoTomlTextArea').value;
try {
const response = await fetch('/save_cargo_toml', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(aimCargoToml),
});
if (!response.ok) {
throw new Error(await response.text());
}
await fetchCargoToml();
} catch (error) {
console.error('Failed to save Cargo.toml:', error);
}
});

window.onload = async () => {
await fetchCurrentDir();
await fetchCargoToml();
await fetchFeatures();
};
</script>

Expand Down
1 change: 1 addition & 0 deletions zino-cli/src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl Init {
return Err(Error::new("current directory is already a Rust project"));
}
let init_res = self.init_with_template();
// must clean the temporary template directory after the initialization
clean_template_dir(TEMPORARY_TEMPLATE_PATH);
match init_res {
Ok(_) => {
Expand Down
1 change: 1 addition & 0 deletions zino-cli/src/cli/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ impl New {
pub fn run(self) -> Result<(), Error> {
let project_dir_already_exists = self.check_project_dir_status()?;
let new_res = self.new_with_template();
// must clean the temporary template directory after the initialization
clean_template_dir(TEMPORARY_TEMPLATE_PATH);
match new_res {
Ok(_) => {
Expand Down
89 changes: 83 additions & 6 deletions zino-cli/src/cli/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use axum::{
};
use clap::Parser;
use include_dir::Dir;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use std::{env, fs};
use toml_edit::{Array, DocumentMut as Document};
use zino::prelude::*;
Expand Down Expand Up @@ -34,7 +34,9 @@ impl Serve {
.route("/current_dir", get(get_current_dir))
.route("/update_current_dir/:path", post(update_current_dir))
.route("/get_current_cargo_toml", get(get_current_cargo_toml))
.route("/generate_cargo_toml", post(generate_cargo_toml))])
.route("/generate_cargo_toml", post(generate_cargo_toml))
.route("/save_cargo_toml", post(save_cargo_toml))
.route("/get_current_features", get(get_current_features))])
.run();
Ok(())
}
Expand Down Expand Up @@ -116,13 +118,62 @@ async fn update_current_dir(Path(path): Path<String>) -> impl IntoResponse {
}

/// Features struct.
#[derive(Debug, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Default)]
struct Features {
zino_feature: Vec<String>,
core_feature: Vec<String>,
}

/// Generates dependencies in `Cargo.toml` file.
impl Features {
/// Get zino-features and zino-core-features from path to Cargo.toml
fn from_path(path: &str) -> Self {
let cargo_toml = fs::read_to_string(path)
.unwrap_or_default()
.parse::<Document>()
.unwrap_or_default();

if cargo_toml.get("dependencies").is_none() {
return Self::default();
}

let zino_features = if cargo_toml["dependencies"].get("zino").is_none()
|| cargo_toml["dependencies"]["zino"].get("features").is_none()
{
vec![]
} else {
match cargo_toml["dependencies"]["zino"]["features"].as_array() {
Some(features) => features
.iter()
.map(|f| f.as_str().unwrap_or_default().to_string())
.collect(),
None => vec![],
}
};

let core_features = if cargo_toml["dependencies"].get("zino-core").is_none()
|| cargo_toml["dependencies"]["zino-core"]
.get("features")
.is_none()
{
vec![]
} else {
match cargo_toml["dependencies"]["zino-core"]["features"].as_array() {
Some(features) => features
.iter()
.map(|f| f.as_str().unwrap_or_default().to_string())
.collect(),
None => vec![],
}
};

Self {
zino_feature: zino_features,
core_feature: core_features,
}
}
}

/// Generates zino-features and zino-core-features from user select options
async fn generate_cargo_toml(mut req: zino::Request) -> zino::Result {
let mut res = zino::Response::default().context(&req);
let body = req.parse_body::<Features>().await?;
Expand All @@ -135,7 +186,7 @@ async fn generate_cargo_toml(mut req: zino::Request) -> zino::Result {
return Ok(res.into());
}
};
let mut cargo_toml = match current_cargo_toml_content.parse::<Document>(){
let mut cargo_toml = match current_cargo_toml_content.parse::<Document>() {
Ok(doc) => doc,
Err(err) => {
res.set_code(axum::http::StatusCode::INTERNAL_SERVER_ERROR);
Expand Down Expand Up @@ -168,7 +219,6 @@ async fn generate_cargo_toml(mut req: zino::Request) -> zino::Result {
cargo_toml["dependencies"]["zino-core"]["features"] = toml_edit::value(core_feature);
}


let options = taplo::formatter::Options {
compact_arrays: false,
compact_inline_tables: false,
Expand All @@ -182,3 +232,30 @@ async fn generate_cargo_toml(mut req: zino::Request) -> zino::Result {
res.set_data(&formatted_toml);
Ok(res.into())
}

/// Returns a `Features` struct from current_dir/Cargo.toml.
async fn get_current_features(req: zino::Request) -> zino::Result {
let mut res = zino::Response::default().context(&req);
let features = Features::from_path("./Cargo.toml");
res.set_content_type("application/json");
res.set_data(&features);
Ok(res.into())
}

/// Saves the content of `Cargo.toml` file.
async fn save_cargo_toml(mut req: zino::Request) -> zino::Result {
let mut res = zino::Response::default().context(&req);

let body = req.parse_body::<String>().await?;

match fs::write("./Cargo.toml", body) {
Ok(_) => {
res.set_code(axum::http::StatusCode::OK);
}
Err(err) => {
res.set_code(axum::http::StatusCode::INTERNAL_SERVER_ERROR);
res.set_data(&err.to_string());
}
}
Ok(res.into())
}

0 comments on commit 5f46b18

Please sign in to comment.