teo_generator/admin/
mod.rs1pub mod sign_in_index_ts;
2pub mod sign_in_keys_ts;
3pub mod preferences_ts;
4pub mod default_preferences_ts;
5pub mod sign_in_form_tsx;
6pub mod translations_index_ts;
7pub mod translations_init_ts;
8pub mod translations_lang_index_ts;
9pub mod translations_languages_ts;
10pub mod pages_index_index_ts;
11pub mod pages_page_stack_default_item_keys_tsx;
12pub mod pages_render_default_stack_item_tsx;
13pub mod pages_page_dashboard;
14pub mod pages_page_form;
15pub mod pages_page_form_page;
16pub mod pages_page_index;
17pub mod pages_page_records;
18pub mod pages_page_records_list;
19pub mod webpack_config_ts;
20pub mod enum_definitions_ts;
21
22use inflector::Inflector;
23use itertools::Itertools;
24use teo_runtime::config::admin::Admin;
25use teo_runtime::namespace::Namespace;
26use teo_result::Result;
27use serde::Deserialize;
28use serde_json::json;
29use teo_runtime::config::client::{Client, ClientLanguage, TypeScriptHTTPProvider};
30use teo_runtime::config::server::Server;
31use once_cell::sync::Lazy;
32use crate::admin::default_preferences_ts::generate_default_preferences_ts;
33use crate::admin::enum_definitions_ts::generate_enum_definitions_ts;
34use crate::admin::pages_index_index_ts::generate_pages_index_index_ts;
35use crate::admin::pages_page_dashboard::generate_pages_page_dashboard_tsx;
36use crate::admin::pages_page_form::generate_pages_page_form_tsx;
37use crate::admin::pages_page_form_page::generate_pages_page_form_page_tsx;
38use crate::admin::pages_page_index::generate_pages_page_index_tsx;
39use crate::admin::pages_page_records::generate_pages_page_records_tsx;
40use crate::admin::pages_page_records_list::generate_pages_page_records_list_tsx;
41use crate::admin::pages_page_stack_default_item_keys_tsx::generate_pages_stack_default_item_keys_tsx;
42use crate::admin::pages_render_default_stack_item_tsx::generate_pages_render_default_stack_item_tsx;
43use crate::admin::preferences_ts::generate_preferences_ts;
44use crate::admin::sign_in_form_tsx::generate_sign_in_form_tsx;
45use crate::admin::sign_in_index_ts::generate_sign_in_index_ts;
46use crate::admin::sign_in_keys_ts::generate_sign_in_keys_ts;
47use crate::admin::translations_index_ts::generate_translations_index_ts;
48use crate::admin::translations_init_ts::generate_translations_init_ts;
49use crate::admin::translations_lang_index_ts::generate_translations_lang_index_ts;
50use crate::admin::translations_languages_ts::generate_translations_languages_ts;
51use crate::admin::webpack_config_ts::generate_webpack_config_ts;
52use crate::utils::file::FileUtil;
53use crate::utils::update_package_json_version::update_package_json_version;
54
55static FILE_ADDRESS: Lazy<String> = Lazy::new(|| {
56 format!("https://raw.githubusercontent.com/teodevgroup/teo-admin-dev/{}/", env!("CARGO_PKG_VERSION"))
57});
58
59static FILE_JSON: &'static str = ".generator/data/fileList.json";
60
61#[derive(Deserialize)]
62struct FileList {
63 generated: Vec<String>,
64 extended: Vec<String>,
65}
66
67pub async fn generate(main_namespace: &Namespace, admin: &Admin, server: &Server) -> Result<()> {
68 let dest_dir = std::env::current_dir()?.join(admin.dest.as_str());
69 let file_util = FileUtil::new(dest_dir.clone());
70 file_util.ensure_root_directory().await?;
71 let file_list = reqwest::get(FILE_ADDRESS.to_owned() + FILE_JSON)
73 .await?
74 .json::<FileList>()
75 .await?;
76 for extended_file in &file_list.extended {
77 let file_location = dest_dir.join(extended_file);
78 if !file_location.exists() {
79 create_file_from_remote_source(extended_file, &file_util).await?;
80 }
81 }
82 for generated_file in &file_list.generated {
83 create_file_from_remote_source(generated_file, &file_util).await?;
84 }
85 let custom_lib = dest_dir.as_path().join("src/lib/custom");
87 let custom_components = dest_dir.as_path().join("src/components/custom");
88 file_util.ensure_directory(custom_lib.as_os_str().to_str().unwrap()).await?;
89 file_util.ensure_directory(custom_components.as_os_str().to_str().unwrap()).await?;
90
91 generate_sign_in_index_ts(main_namespace, &file_util).await?;
95 generate_sign_in_keys_ts(main_namespace, &file_util).await?;
96 generate_sign_in_form_tsx(main_namespace, &file_util).await?;
97
98 generate_preferences_ts(main_namespace, &file_util).await?;
100 generate_default_preferences_ts(main_namespace, &admin.languages, &file_util).await?;
101
102 generate_enum_definitions_ts(main_namespace, &file_util).await?;
104
105 create_file_from_remote_source("src/lib/generated/translations/static.ts", &file_util).await?;
108 generate_translations_index_ts(main_namespace, &file_util).await?;
109 generate_translations_init_ts(&admin.languages, &file_util).await?;
110 generate_translations_languages_ts(&admin.languages, &file_util).await?;
111 let index_ts = "src/lib/extended/translations/index.ts";
113 let file_location = dest_dir.join(index_ts);
114 if !file_location.exists() {
115 create_file_from_remote_source(index_ts, &file_util).await?;
116 }
117 for lang in admin.languages.iter() {
118 create_file_from_remote_source(&format!("src/lib/generated/translations/{}/static.ts", lang.as_str()), &file_util).await?;
120 generate_translations_lang_index_ts(lang.as_str(), main_namespace, &file_util).await?;
121 let location = dest_dir.join(format!("src/lib/extended/translations/{}.ts", lang.as_str()));
123 if !file_location.exists() {
124 create_file_from_remote_source(location.to_str().unwrap(), &file_util).await?;
125 }
126 }
127
128 generate_pages_index_index_ts(main_namespace, &file_util).await?;
132
133 generate_pages_stack_default_item_keys_tsx(main_namespace, &file_util).await?;
135 generate_pages_render_default_stack_item_tsx(main_namespace, &file_util).await?;
136
137 for m in main_namespace.collect_models(|m| m.data().get("admin:ignore").is_none()) {
139 let model_variable_name = m.path().iter().map(|s| s.to_pascal_case()).join("");
140 let path = m.path().join("/");
141 generate_pages_page_dashboard_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
142 generate_pages_page_form_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
143 generate_pages_page_form_page_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
144 generate_pages_page_index_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
145 generate_pages_page_records_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
146 generate_pages_page_records_list_tsx(main_namespace, m, &model_variable_name, &path, &file_util).await?;
147 }
148 file_util.generate_file("README.md", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/admin/readme.md.jinja"))).await?;
150
151 generate_webpack_config_ts(server.bind.1.to_string(), &file_util).await?;
153
154 let remote_json_string = fetch_remote_content("package.json").await?;
156 let remote_json_data: serde_json::Value = serde_json::from_str(&remote_json_string).unwrap();
157 let dependencies = remote_json_data.get("dependencies").unwrap();
158 let mut dev_dependencies = remote_json_data.get("devDependencies").unwrap().clone();
159 dev_dependencies.as_object_mut().unwrap().shift_remove("glob").unwrap();
160 let new_json_data = json!({
161 "name": "admin-dashboard",
162 "version": "0.0.1",
163 "description": "This project is generated with Teo.",
164 "private": true,
165 "scripts": {
166 "start": "npx webpack-dev-server",
167 },
168 "dependencies": dependencies.clone(),
169 "devDependencies": dev_dependencies.clone(),
170 });
171 if file_util.generate_file_if_not_exist("package.json", serde_json::to_string(&new_json_data).unwrap()).await? {
172 let json_data = std::fs::read_to_string(file_util.get_file_path("package.json"))
174 .expect("Unable to read package.json");
175 file_util.generate_file("package.json", update_json_version_and_deps(json_data, dependencies, &dev_dependencies)).await?;
176 }
177 crate::client::generate(main_namespace, &Client {
179 provider: ClientLanguage::TypeScript(TypeScriptHTTPProvider::Fetch),
180 dest: dest_dir.as_path().join("src/lib/generated/teo").to_str().unwrap().to_owned(),
181 package: false,
182 host: admin.host.clone(),
183 object_name: "teo".to_owned(),
184 git_commit: false,
185 }).await?;
186 Ok(())
187}
188
189fn update_json_version_and_deps(json_data: String, dependencies: &serde_json::Value, dev_dependencies: &serde_json::Value) -> String {
190 let version_updated_json_data = update_package_json_version(json_data);
191 let mut json_value: serde_json::Value = serde_json::from_str(&version_updated_json_data).unwrap();
192 let deps = json_value.get_mut("dependencies").unwrap();
193 let deps_object = deps.as_object_mut().unwrap();
194 let source_deps = dependencies.as_object().unwrap();
195 for (k, v) in source_deps {
196 if deps_object.get(k).is_none() {
197 deps_object.insert(k.to_owned(), v.clone());
198 }
199 }
200 let dev_deps = json_value.get_mut("devDependencies").unwrap();
201 let dev_deps_object = dev_deps.as_object_mut().unwrap();
202 let source_dev_deps = dev_dependencies.as_object().unwrap();
203 for (k, v) in source_dev_deps {
204 if dev_deps_object.get(k).is_none() {
205 dev_deps_object.insert(k.to_owned(), v.clone());
206 }
207 }
208 serde_json::to_string(&json_value).unwrap()
209}
210
211async fn fetch_remote_content(location: &str) -> Result<String> {
212 Ok(reqwest::get(FILE_ADDRESS.to_owned() + location)
213 .await?
214 .text()
215 .await?)
216}
217
218async fn create_file_from_remote_source(location: &str, file_util: &FileUtil) -> Result<()> {
219 let content = fetch_remote_content(location).await?;
220 file_util.ensure_directory_and_generate_file(location, content).await
221}