use std::cell::RefCell; use std::io::Cursor; use std::collections::{HashMap, self}; use std::rc::Rc; use gloo::console::{console_dbg, console}; use gloo::file::callbacks::FileReader; use gloo::file::File; use gloo::storage::{LocalStorage, Storage}; use web_sys::{DragEvent, Event, FileList, HtmlInputElement, MouseEvent}; use yew::html::TargetCast; use yew::{html, Callback, Component, Context, Html}; use crate::generate_sql::{SQLValueGuess, generate_table_guessess, generate_fake_entries}; use crate::magicdraw_parser::{parse_project, SQLTableCollection, SQLTable}; use crate::components::sql_column_info::SQLTableColumnInfo; const COLLECTION_STORE_KEY: &str = "current_collection"; const DEFAULT_ROWS_PER_TABLE: u32 = 20; pub enum Msg { Noop, Loaded(String, Vec), UploadProject(File), UpdateCurrentProject(Option), UpdateGenarator(String, SQLValueGuess), ShowNextTable, ShowPrevTable, AllGoodConfirmation, GenerateSQL, UpdateRowsPerTable(u32), } pub struct App { active_readers: HashMap, current_collection: Option>>, current_guessess: Vec>>>, currently_shown_table: usize, all_good_confirmed: bool, generated_sql: Option, rows_per_table: u32 } impl Component for App { type Message = Msg; type Properties = (); fn create(_ctx: &Context) -> Self { let mut current_guessess = vec![]; let mut current_collection = None; if let Ok(collection) = LocalStorage::get::("current_collection") { for table in &collection.tables { let guess = generate_table_guessess(table); current_guessess.push(Rc::new(RefCell::new(guess))); } current_collection = Some(collection.tables.into_iter().map(Rc::new).collect()); } Self { active_readers: HashMap::default(), current_collection, currently_shown_table: 0, all_good_confirmed: true, // TODO: make this false, by default generated_sql: None, current_guessess, rows_per_table: DEFAULT_ROWS_PER_TABLE } } fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { match msg { Msg::Loaded(file_name, data) => { if file_name.ends_with(".mdzip") { let cursor = Cursor::new(&data); let mut collections = parse_project(cursor).expect("oops"); if collections.len() >= 1 { let msg = Self::update_current_collection(Some(collections.remove(0))); ctx.link().send_message(msg); } // TODO: show error message } self.active_readers.remove(&file_name); true } Msg::UploadProject(file) => { let file_name = file.name(); let task = { let link = ctx.link().clone(); let file_name = file_name.clone(); gloo::file::callbacks::read_as_bytes(&file, move |res| { // TODO: show error message link.send_message(Msg::Loaded( file_name, res.expect("failed to read file"), )) }) }; self.active_readers.insert(file_name, task); true }, Msg::Noop => false, Msg::UpdateCurrentProject(collection) => { if let Some(collection) = collection { LocalStorage::set(COLLECTION_STORE_KEY, &collection).unwrap(); self.currently_shown_table = 0; self.all_good_confirmed = false; self.generated_sql = None; self.current_guessess = vec![]; for table in &collection.tables { let guess = generate_table_guessess(table); self.current_guessess.push(Rc::new(RefCell::new(guess))); } self.current_collection = Some(collection.tables.into_iter().map(Rc::new).collect()); } else { LocalStorage::delete(COLLECTION_STORE_KEY); self.current_collection = None } true }, Msg::ShowNextTable => { if let Some(collection) = &self.current_collection { self.currently_shown_table = (self.currently_shown_table + 1).min(collection.len()-1); return true; } false }, Msg::ShowPrevTable => { if self.currently_shown_table > 0 { self.currently_shown_table = self.currently_shown_table - 1; return true; } false }, Msg::AllGoodConfirmation => { self.all_good_confirmed = true; true }, Msg::UpdateGenarator(column, generator) => { let mut guessess = self.current_guessess[self.currently_shown_table].borrow_mut(); let entry = guessess.get_mut(&column).unwrap(); *entry = generator; true }, Msg::GenerateSQL => { let tables = self.current_collection.as_ref().unwrap(); let guessess = self.current_guessess.iter().map(|v| v.borrow()).collect(); // TODO: show error message if let Ok(result) = generate_fake_entries(tables, &guessess, self.rows_per_table) { self.generated_sql = Some(result) } else { self.generated_sql = None } true }, Msg::UpdateRowsPerTable(rows_per_table) => { self.rows_per_table = rows_per_table; false } } } fn view(&self, ctx: &Context) -> Html { html! {

{ "🪄 MagicDraw SQL Data Generator" }

{ self.show_step1(ctx) } if self.current_collection.is_some() { { self.show_step2(ctx) } if self.all_good_confirmed { { self.show_step3(ctx) } if self.generated_sql.is_some() { { self.show_step4(ctx) } } } }
} } } impl App { fn show_step1(&self, ctx: &Context) -> Html { let prevent_default_cb = Callback::from(|event: DragEvent| { event.prevent_default(); }); html! {

{ "1. Upload " } {".mdzip"} { " project" }

{ "NOTE: This relies on the fact, that you have a .dll script configured" }

} } fn show_step2(&self, ctx: &Context) -> Html { let collection = self.current_collection.as_ref().unwrap(); html! {

{ "2. Make sure everything looks 👌" }

{ self.currently_shown_table + 1 } { " / " } { collection.len() }
} } fn show_step3(&self, ctx: &Context) -> Html { let on_rows_changed = ctx.link().callback(|e: Event| { let value_str = e.target_unchecked_into::().value(); let value = value_str.parse().unwrap_or(DEFAULT_ROWS_PER_TABLE); Msg::UpdateRowsPerTable(value) }); html! {

{ "3. Final settings" }

} } fn show_step4(&self, ctx: &Context) -> Html { let sql = self.generated_sql.as_ref().unwrap(); html! {

{ "4. Copy & Paste" }

					{ sql }
				
} } fn upload_project(files: Option) -> Msg { if let Some(files) = files { let file = js_sys::try_iter(&files) .unwrap() .unwrap() .next() .map(|v| web_sys::File::from(v.unwrap())) .map(File::from) .unwrap(); Msg::UploadProject(file) } else { Msg::Noop } } pub fn update_current_collection(current_collection: Option) -> Msg { Msg::UpdateCurrentProject(current_collection) } }