Skip to content

Commit 0c5717f

Browse files
committed
v0.13.0 cli and web
1 parent eb8f647 commit 0c5717f

File tree

8 files changed

+117
-43
lines changed

8 files changed

+117
-43
lines changed

Cargo.lock

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
[package]
22
name = "svg2gcode-cli"
3-
version = "0.0.12"
3+
version = "0.0.13"
44
authors = ["Sameer Puri <crates@purisa.me>"]
55
edition = "2021"
66
description = "Command line interface for svg2gcode"
77
repository = "https://github.com/sameer/svg2gcode"
88
license = "MIT"
99

1010
[dependencies]
11-
svg2gcode = { version = "0.2.3", features = ["serde"]}
12-
env_logger = { version = "0", default-features = false, features = ["atty", "termcolor", "humantime"] }
11+
svg2gcode = { version = "0.3.0", features = ["serde"] }
12+
env_logger = { version = "0", default-features = false, features = [
13+
"atty",
14+
"termcolor",
15+
"humantime",
16+
] }
1317
log = "0"
1418
g-code = "0.4.2"
1519
codespan-reporting = "0.11"

cli/src/main.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use g_code::{
22
emit::{format_gcode_io, FormatOptions},
33
parse::snippet_parser,
44
};
5-
use log::info;
5+
use log::{error, info};
66
use roxmltree::ParsingOptions;
77
use std::{
88
env,
@@ -13,7 +13,9 @@ use std::{
1313
use structopt::StructOpt;
1414
use svgtypes::LengthListParser;
1515

16-
use svg2gcode::{svg2program, ConversionOptions, Machine, Settings, SupportedFunctionality};
16+
use svg2gcode::{
17+
svg2program, ConversionOptions, Machine, Settings, SupportedFunctionality, Version,
18+
};
1719

1820
#[derive(Debug, StructOpt)]
1921
#[structopt(name = "svg2gcode", author, about)]
@@ -158,6 +160,25 @@ fn main() -> io::Result<()> {
158160
settings.postprocess.newline_before_comment = newline_before_comment;
159161
}
160162

163+
if let Version::Unknown(ref unknown) = settings.version {
164+
error!(
165+
"Your settings use an unknown version. Your version: {unknown}, latest: {}. See {} to download the latest CLI version.",
166+
Version::latest(),
167+
env!("CARGO_PKG_REPOSITORY"),
168+
);
169+
std::process::exit(1);
170+
}
171+
172+
let old_version = settings.version.clone();
173+
if let Err(()) = settings.try_upgrade() {
174+
error!(
175+
"Your settings are out of date and require manual intervention. Your version: {old_version}, latest: {}. See {} for instructions.",
176+
Version::latest(),
177+
env!("CARGO_PKG_REPOSITORY"),
178+
);
179+
std::process::exit(1);
180+
}
181+
161182
settings
162183
};
163184

web/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "svg2gcode-web"
3-
version = "0.0.12"
3+
version = "0.0.13"
44
authors = ["Sameer Puri <crates@purisa.me>"]
55
edition = "2021"
66
description = "Convert vector graphics to g-code for pen plotters, laser engravers, and other CNC machines"
@@ -10,7 +10,7 @@ license = "MIT"
1010

1111
[dependencies]
1212
wasm-bindgen = "0.2"
13-
svg2gcode = { version = "0.2.3", features = ["serde"] }
13+
svg2gcode = { version = "0.3.0", features = ["serde"] }
1414
roxmltree = "0.19"
1515
g-code = "0.4.2"
1616
codespan-reporting = "0.11"

web/src/forms/mod.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use gloo_file::{
55
use js_sys::TypeError;
66
use roxmltree::{Document, ParsingOptions};
77
use std::{convert::TryInto, path::Path};
8-
use svg2gcode::Settings;
8+
use svg2gcode::{Settings, Version};
99
use wasm_bindgen::JsCast;
1010
use wasm_bindgen_futures::JsFuture;
1111
use web_sys::{window, Event, FileList, HtmlElement, HtmlInputElement, Response};
@@ -267,8 +267,31 @@ pub fn import_export_modal() -> Html {
267267
});
268268

269269
match res {
270-
Ok(settings) => {
271-
import_state.set(Some(Ok(settings)));
270+
Ok(Settings { version: Version::Unknown(unknown), .. }) => {
271+
import_state.set(Some(Err(
272+
format!(
273+
"Your settings use an unknown version. \
274+
Your version: {unknown}, latest: {}. \
275+
Try refreshing this page to get the latest version of the tool.",
276+
Version::latest(),
277+
)
278+
)));
279+
}
280+
Ok(mut settings) => {
281+
let old_version = settings.version.clone();
282+
import_state.set(Some(
283+
if let Err(()) = settings.try_upgrade() {
284+
Err(format!(
285+
"Your imported settings are out of date and require manual intervention. \
286+
Your version: {old_version}, latest: {}. \
287+
See {} for instructions.",
288+
Version::latest(),
289+
env!("CARGO_PKG_REPOSITORY")
290+
))
291+
} else {
292+
Ok(settings)
293+
})
294+
);
272295
}
273296
Err(err) => {
274297
import_state.set(Some(Err(err)));
@@ -284,7 +307,7 @@ pub fn import_export_modal() -> Html {
284307
let import_state = import_state.clone();
285308
let close_ref = close_ref.clone();
286309
app_dispatch.reduce_mut_callback(move |app| {
287-
if let Some(Ok(ref settings)) = *import_state {
310+
if let Some(Ok(settings)) = import_state.as_ref() {
288311
app.settings = settings.clone();
289312
// App only hydrates the form on start now, so need to do it again here
290313
form_dispatch.reduce_mut(|form| *form = (&app.settings).into());

web/src/main.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,16 @@ fn app() -> Html {
3838
// Having separate stores is somewhat of an anti-pattern in Redux,
3939
// but there's no easy way to do hydration after the app state is
4040
// restored from local storage.
41-
let hydrated_form = use_state(|| false);
42-
if !*hydrated_form {
43-
let hydrated_form_state = FormState::from(&app_store.settings);
44-
form_dispatch.reduce_mut(|state| *state = hydrated_form_state);
45-
hydrated_form.set(true);
41+
let upgraded_settings_and_hydrated_form = use_state(|| false);
42+
if !*upgraded_settings_and_hydrated_form {
43+
app_dispatch.reduce_mut(|app| {
44+
if let Err(_) = app.settings.try_upgrade() {
45+
unreachable!("No breaking upgrades yet!")
46+
}
47+
let hydrated_form_state = FormState::from(&app_store.settings);
48+
form_dispatch.reduce_mut(|state| *state = hydrated_form_state);
49+
});
50+
upgraded_settings_and_hydrated_form.set(true);
4651
}
4752

4853
let generate_disabled = *generating || app_store.svgs.is_empty();

web/src/state.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use serde::{Deserialize, Serialize};
22
use std::{convert::TryInto, num::ParseFloatError};
33
use svg2gcode::{
4-
ConversionConfig, MachineConfig, PostprocessConfig, Settings, SupportedFunctionality,
4+
ConversionConfig, MachineConfig, PostprocessConfig, Settings, SupportedFunctionality, Version,
55
};
66
use svgtypes::Length;
77
use thiserror::Error;
@@ -83,6 +83,7 @@ impl<'a> TryInto<Settings> for &'a FormState {
8383
line_numbers: self.line_numbers,
8484
newline_before_comment: self.newline_before_comment,
8585
},
86+
version: Version::latest(),
8687
})
8788
}
8889
}

web/src/ui/mod.rs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::fmt::Display;
2-
use web_sys::{Event, FileList, HtmlInputElement, InputEvent, MouseEvent};
2+
use web_sys::{Event, FileList, HtmlInputElement, InputEvent, InputEventInit, MouseEvent};
33
use yew::{
44
classes, function_component, html, use_force_update, use_node_ref, use_state,
55
virtual_dom::{VChild, VNode},
@@ -93,12 +93,15 @@ where
9393
trigger.force_update();
9494
}
9595

96-
if let (false, Some(default), Some(input_element)) = (
97-
*applied_default_value,
98-
props.default.as_ref(),
99-
node_ref.cast::<HtmlInputElement>(),
100-
) {
101-
input_element.set_value(&default.to_string());
96+
if let (false, Some(input_element)) =
97+
(*applied_default_value, node_ref.cast::<HtmlInputElement>())
98+
{
99+
if let Some(d) = props.default.as_ref() {
100+
input_element.set_value(&d.to_string());
101+
input_element
102+
.dispatch_event(&InputEvent::new("input").unwrap())
103+
.unwrap();
104+
}
102105
applied_default_value.set(true);
103106
}
104107

@@ -346,30 +349,46 @@ where
346349
// so the noderef becomes valid.
347350
let first_render = use_state(|| true);
348351
let trigger = use_force_update();
349-
let applied_default_value = use_state(|| false);
350352
let node_ref = use_node_ref();
351353

352354
if *first_render {
353355
first_render.set(false);
354356
trigger.force_update();
355357
}
356358

357-
if let (false, Some(default), Some(input_element)) = (
358-
*applied_default_value,
359-
props.default.as_ref(),
360-
node_ref.cast::<HtmlInputElement>(),
361-
) {
362-
input_element.set_value(default.as_ref());
363-
applied_default_value.set(true);
359+
let user_edited = use_state(|| false);
360+
let last_default_value = use_state(|| None);
361+
if let Some(input_element) = node_ref.cast::<HtmlInputElement>() {
362+
if !*user_edited && props.default != *last_default_value {
363+
if let Some(d) = props.default.as_ref() {
364+
input_element.set_value(d);
365+
} else {
366+
input_element.set_value("");
367+
}
368+
let mut init = InputEventInit::new();
369+
init.data(Some("ignore"));
370+
input_element
371+
.dispatch_event(&InputEvent::new_with_event_init_dict("input", &init).unwrap())
372+
.unwrap();
373+
last_default_value.set(props.default.clone());
374+
}
364375
}
365376

377+
let prop_oninput = props.oninput.clone();
378+
let oninput = Callback::from(move |event: InputEvent| {
379+
if !event.data().map_or(false, |d| d == "ignore") {
380+
prop_oninput.emit(event);
381+
user_edited.set(true);
382+
}
383+
});
384+
366385
html! {
367386
<>
368387
<label class="form-label" for={id.clone()}>
369388
{ props.label }
370389
</label>
371390
<div class={classes!(if success || error { Some("has-icon-right") } else { None })}>
372-
<textarea class="form-input" id={id} oninput={props.oninput.clone()}
391+
<textarea class="form-input" id={id} oninput={oninput}
373392
ref={node_ref}
374393
placeholder={props.placeholder.as_ref().cloned()}
375394
rows={props.rows.as_ref().map(ToString::to_string)}

0 commit comments

Comments
 (0)