diff --git a/REBRAND.md b/REBRAND.md new file mode 100644 index 0000000..9ca5dc6 --- /dev/null +++ b/REBRAND.md @@ -0,0 +1,48 @@ +# OneCAD Simulation rebrand map (identity layer) + +OneCAD Simulation is the OneBSpace fork of FieldCraft (a pure-Rust CAE app: FEA, meshing, +thermal, LBM CFD, with a WASM web app at `apps/fieldcraft-web`). The rebrand is **source-level** +for everything the user can see or click; only the compatibility layer keeps upstream names (so +`.fieldcraft` files, crate names, storage keys and internal identifiers stay upstream-compatible, +and every upstream sync stays a clean merge). Files tagged `// OneBSpace (OneCAD Simulation):` +are downstream-only deltas — one tag per edited site, above or beside the change, so the whole +fork layer can be found with `grep -rn "OneBSpace (OneCAD Simulation)"`. + +## Rebranded in source (user-visible) + +| Layer | Change | +|---|---| +| Web page | `OneCAD Simulation`, description and social-card meta renamed; upstream's `tangency-labs.github.io/fieldcraft` `og:url`/`og:image`/`twitter:image` dropped; loading, no-JavaScript and could-not-start text say "OneCAD Simulation" (`apps/fieldcraft-web/index.html`) | +| App bar | upstream's drawn fringe-cube vector mark dropped; a painted `OneCAD Simulation` wordmark (`appbar.rs::APP_NAME`) shows in **every** width variant — the compact bar keeps the name and the quick actions start after the measured wordmark (`bar_layout` gained a `name_w` argument) | +| Help menu | Samples, navigation help, Crash Reports…, Settings… and the version label `OneCAD Simulation {VERSION}` remain; upstream's `Report a Bug…` (GitHub draft), `Check for Updates` and `Reinstall FieldCraft…` items and their handler branches are removed (`appbar.rs::help_menu`) | +| Bug/crash reports | fully local: the Report-a-Bug form's `Open GitHub Issue` became a `Copy report` button — the draft (title, fields, session) goes to the clipboard and attachments to the local `bug-reports/` folder; nothing opens a browser, `ISSUE_URL` is never opened (`report.rs::copy_report`); crash questions/headings say "OneCAD Simulation closed unexpectedly / hit an internal error" | +| Crash messages | the engine's unclean-exit and native-crash messages (rendered in the crash dialog and the copied report) name the fork (`engine/src/crash.rs`) | +| Command catalogue | `diagnostics.bug_report` and `app.update.check` palette help texts describe the local draft / name the fork (`engine/src/cmd/diagnostics.rs`, `engine/src/cmd/update.rs`) | +| Updates (desktop-only) | every status line, the notice and the install dialog say "OneCAD Simulation" (`updates.rs`); the web build has no update host, so none of this runs in the browser; "What's new"/release URLs stay desktop-only logic, rebranded text only | +| Privacy | consent question and dialog title, Settings copy and tooltips say "OneCAD Simulation"; the upstream GitHub `PRIVACY_URL` is no longer rendered as a link nor opened — the privacy note is plain text (`privacy.rs`); the constant is kept for reference | +| Navigation | the default mouse-mapping preset's label is "OneCAD Simulation" (its `id: "fieldcraft"` stays, preferences depend on it) | +| Desktop window | window title / `run_native` app name "OneCAD Simulation" (`apps/fieldcraft/src/main.rs`; the `APP_ID` reverse-DNS id stays) | +| Attachments | the bug-report session attachment is `onecadsim-session.json` (`engine/src/bug_report.rs::SESSION_FILE`); the model attachment keeps the `.fieldcraft` name | + +## Stays upstream (compatibility & scale) + +- **The `.fieldcraft` file-format extension** (and `model.fieldcraft` attachment naming); crate + names and the Cargo workspace layout — untouched, so upstream syncs stay mergeable. +- **localStorage keys** (`fieldcraft-recovery/`, `fieldcraft-prefs`) and the browser recovery + folder layout. +- **HTML element ids** (`fieldcraft_canvas`, `fieldcraft_loading`) and the trunk tags in + `apps/fieldcraft-web/index.html`. +- **Environment variable names** (`FIELDCRAFT_POSTHOG_KEY`, `FIELDCRAFT_TELEMETRY`, + `FIELDCRAFT_CONTROL_PORT`, …). Telemetry logic is untouched: the Odoo build simply does not set + `FIELDCRAFT_POSTHOG_KEY`, so the PostHog sender stays inert; no key or host URL is surfaced in + the UI. +- **Internal identifiers**: egui window/id salts (`fc_appbar`, `fc_report_bug`, …), command ids + (`diagnostics.bug_report`), the `fieldcraft` nav-preset id, `SESSION_FILE`/`ISSUE_URL` API + names, the `fieldcraft-cli` binary name quoted in report text. +- Desktop-only updater internals (release URLs, package layouts) keep upstream strings — + unreachable from the web build. + +## Not touched here + +`crates/ui-egui/src/files.rs` and `apps/fieldcraft-web/src/{web,main}.rs` plus `odoo/*` are owned +by other agents in this task train; their user-visible strings are handled there. diff --git a/apps/fieldcraft/src/main.rs b/apps/fieldcraft/src/main.rs index b422be8..352ce4f 100644 --- a/apps/fieldcraft/src/main.rs +++ b/apps/fieldcraft/src/main.rs @@ -248,7 +248,9 @@ fn main() -> eframe::Result { crash::phase("window"); let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default() - .with_title("FieldCraft") + // OneBSpace (OneCAD Simulation): the window title names the fork (the APP_ID, which + // the packaged .desktop entries and the bundle id match, stays upstream). + .with_title("OneCAD Simulation") .with_app_id(APP_ID) .with_icon(app_icon()) .with_inner_size([1400.0, 900.0]) @@ -265,7 +267,8 @@ fn main() -> eframe::Result { ..Default::default() }; eframe::run_native( - "FieldCraft", + // OneBSpace (OneCAD Simulation): the app name in the window title. + "OneCAD Simulation", options, Box::new(move |cc| { crash::phase("app setup"); diff --git a/crates/engine/src/bug_report.rs b/crates/engine/src/bug_report.rs index 2b4beeb..2784eea 100644 --- a/crates/engine/src/bug_report.rs +++ b/crates/engine/src/bug_report.rs @@ -21,7 +21,9 @@ pub const ISSUE_URL: &str = "https://github.com/tangency-labs/fieldcraft/issues/ /// The longest link a draft opens: GitHub refuses new-issue links much past 8 KB. pub const MAX_URL: usize = 7000; /// The session file a draft attaches. -pub const SESSION_FILE: &str = "fieldcraft-session.json"; +// OneBSpace (OneCAD Simulation): the attachment name carries the fork's mark; the internal API +// name (`SESSION_FILE`) stays upstream. +pub const SESSION_FILE: &str = "onecadsim-session.json"; /// The model file a draft attaches. pub const MODEL_FILE: &str = "model.fieldcraft"; /// Backtrace frames a crash's draft quotes. @@ -158,8 +160,9 @@ pub fn draft(input: &Input, version: &str) -> Draft { let crash = input.crash.as_ref(); let mut title = input.title.trim().to_string(); if title.is_empty() { + // OneBSpace (OneCAD Simulation): the fork's name in the drafted title. title = match crash.and_then(|c| c.get("kind")).and_then(Value::as_str) { - Some("unclean_exit") => "FieldCraft closed unexpectedly".to_string(), + Some("unclean_exit") => "OneCAD Simulation closed unexpectedly".to_string(), Some(_) => "Internal error".to_string(), None => match input.observed.trim().lines().next().filter(|l| !l.is_empty()) { Some(line) => format!("Bug: {}", line.chars().take(100).collect::<String>()), @@ -224,14 +227,16 @@ pub fn draft(input: &Input, version: &str) -> Draft { } else { let text = serde_json::to_string_pretty(script).unwrap_or_default(); evidence.push_str(&format!( - "\nThe session is too long for this form: FieldCraft saved it as `{SESSION_FILE}` and copied it to the clipboard. Attach the file here (drag it in) or paste it.\n" + // OneBSpace (OneCAD Simulation): the fork's name in the evidence text. + "\nThe session is too long for this form: OneCAD Simulation saved it as `{SESSION_FILE}` and copied it to the clipboard. Attach the file here (drag it in) or paste it.\n" )); attachments.insert(0, Attachment { name: SESSION_FILE.into(), bytes: text.clone().into_bytes(), what: "the session's commands".into() }); clipboard = Some(text); } } if model.is_some() { - evidence.push_str(&format!("\nThe model is attached as `{MODEL_FILE}` (drag it in from the folder FieldCraft saved it to).\n")); + // OneBSpace (OneCAD Simulation): the fork's name in the evidence text. + evidence.push_str(&format!("\nThe model is attached as `{MODEL_FILE}` (drag it in from the folder OneCAD Simulation saved it to).\n")); } if url.is_empty() || model.is_some() { let mut f = fields(evidence.clone()); diff --git a/crates/engine/src/cmd/diagnostics.rs b/crates/engine/src/cmd/diagnostics.rs index 324c63f..22e2357 100644 --- a/crates/engine/src/cmd/diagnostics.rs +++ b/crates/engine/src/cmd/diagnostics.rs @@ -43,7 +43,9 @@ pub const CRASH_REPORTS_DELETE: CommandSpec = CommandSpec { pub const BUG_REPORT: CommandSpec = CommandSpec { id: "diagnostics.bug_report", label: "Report a Bug", - params: r#"{"title"?: "…", "observed"?: "what happened", "crash"?: "<crash report id>", "share_session"?: false, "include_model"?: false} — drafts a GitHub bug report: the issue link (the bug form filled with the version, the OS, what happened and, for a crash, where), and the files to attach. Only with share_session does it carry the model's commands, and only with include_model as well the model file. Nothing is sent: the desktop app's Help › Report a Bug shows the draft and opens the link when the user asks"#, + // OneBSpace (OneCAD Simulation): the draft stays local — no GitHub issue link is opened; + // the form's Copy report puts the report on the clipboard and saves attachments to a folder. + params: r#"{"title"?: "…", "observed"?: "what happened", "crash"?: "<crash report id>", "share_session"?: false, "include_model"?: false} — drafts a bug report that stays in the workspace: the version, the OS, what happened and, for a crash, where, and the files to attach. Only with share_session does it carry the model's commands, and only with include_model as well the model file. Nothing is sent: the form's Copy report copies the report to the clipboard and saves the attachments to a local folder"#, form: Some(super::forms::BUG_REPORT), kind: CommandKind::Session, requires: &[], diff --git a/crates/engine/src/cmd/update.rs b/crates/engine/src/cmd/update.rs index debfd5f..4dec6f1 100644 --- a/crates/engine/src/cmd/update.rs +++ b/crates/engine/src/cmd/update.rs @@ -15,7 +15,8 @@ use crate::{CommandKind, CommandSpec, EngineError, Result, Session}; pub const CHECK: CommandSpec = CommandSpec { id: "app.update.check", label: "Check for Updates", - params: r#"{} — asks GitHub Releases for the latest published FieldCraft release and compares it with this version: current, latest, newer, url (its page and release notes), published, signed (whether it can be verified and installed from the app) and asset (the file this install would download; null when it cannot update itself). Reports only: nothing is downloaded or installed. Desktop app and fieldcraft-cli only"#, + // OneBSpace (OneCAD Simulation): the fork's name in the palette help text (desktop-only). + params: r#"{} — asks GitHub Releases for the latest published OneCAD Simulation release and compares it with this version: current, latest, newer, url (its page and release notes), published, signed (whether it can be verified and installed from the app) and asset (the file this install would download; null when it cannot update itself). Reports only: nothing is downloaded or installed. Desktop app and fieldcraft-cli only"#, form: Some(&[]), kind: CommandKind::Session, requires: &[], diff --git a/crates/engine/src/crash.rs b/crates/engine/src/crash.rs index 933cf48..9448cf8 100644 --- a/crates/engine/src/crash.rs +++ b/crates/engine/src/crash.rs @@ -493,7 +493,8 @@ fn hook(info: &std::panic::PanicHookInfo<'_>) -> bool { // Outside any command: what the journal knows has to do. let extra = from_journal(read_live_journal(state), None); if let Some(id) = write_report(state, "panic", Some(&p), extra) { - eprintln!("FieldCraft: internal error; crash report {}", state.dir.join(&id).display()); + // OneBSpace (OneCAD Simulation): the fork's name on the console. + eprintln!("OneCAD Simulation: internal error; crash report {}", state.dir.join(&id).display()); if let Ok(mut j) = state.journal.try_lock() { j.record(&json!({ "reported": id })); } @@ -890,7 +891,9 @@ fn unclean_exit(dir: &Path, build: &Build, journal: &Path) { let p = match &native { Some(n) => native_panic(n, &was, &when, &during, &what), None => Panic { - message: format!("FieldCraft {was} (started {when}) ended without a clean exit {during}"), + // OneBSpace (OneCAD Simulation): the fork's name in the crash message (shown in the + // crash question and in the report the user copies). + message: format!("OneCAD Simulation {was} (started {when}) ended without a clean exit {during}"), location: match (&starting, &doing) { (Some((p, _)), _) => format!("unclean exit during startup: {p}"), (None, c) => format!("unclean exit in {}", c.as_deref().unwrap_or("(between commands)")), @@ -958,7 +961,8 @@ fn native_panic(native: &Value, was: &str, when: &str, during: &str, what: &str) backtrace.push(format!("on thread {t}")); } Panic { - message: format!("FieldCraft {was} (started {when}) crashed with {name} ({code}) in {at} {during}"), + // OneBSpace (OneCAD Simulation): the fork's name in the native-crash message. + message: format!("OneCAD Simulation {was} (started {when}) crashed with {name} ({code}) in {at} {during}"), location: format!("native exception in {at}"), thread: native.get("thread").and_then(Value::as_u64).map_or_else(|| "(unknown)".into(), |t| format!("native thread {t}")), backtrace, diff --git a/crates/ui-egui/src/appbar.rs b/crates/ui-egui/src/appbar.rs index c575dd8..9341c8d 100644 --- a/crates/ui-egui/src/appbar.rs +++ b/crates/ui-egui/src/appbar.rs @@ -61,49 +61,17 @@ fn button_style(t: &Tokens) -> IconButtonStyle { } } -/// FieldCraft's mark: the application icon's fringe cube (`assets/app-icon/icon-small.svg`, after -/// `xtask/src/app_icon.rs`) drawn in code without its tile or streamline: each visible face split -/// into small cells coloured by the fringe band at the cell's centre, shaded per face. -fn mark(p: &egui::Painter, c: egui::Pos2) { - // The cube is 2 units tall on screen (half side 0.5, isometric); draw it 22 points tall. - const S: f32 = 11.0; - const N: usize = 8; - const FRINGE: [(u8, u8, u8); 7] = - [(0x2c, 0x4f, 0xbf), (0x2f, 0x86, 0xe0), (0x22, 0xbc, 0xd8), (0x3f, 0xc5, 0x84), (0xf0, 0xd1, 0x3a), (0xf2, 0x8a, 0x2b), (0xde, 0x3b, 0x2f)]; - const RADII: [f32; 6] = [1.28, 1.07, 0.87, 0.67, 0.47, 0.27]; - let at = |q: [f32; 3]| c + vec2((q[0] - q[1]) * 0.866 * S, ((q[0] + q[1]) * 0.5 - q[2]) * S); - // Each face: origin corner, two edge vectors, and how much it is darkened (0 to 1). - let faces: [([f32; 3], [f32; 3], [f32; 3], f32); 3] = [ - ([-0.5, -0.5, 0.5], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], 0.0), - ([-0.5, 0.5, -0.5], [1.0, 0.0, 0.0], [0.0, 0.0, 1.0], 0.12), - ([0.5, -0.5, -0.5], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], 0.3), - ]; - let point = |o: [f32; 3], u: [f32; 3], v: [f32; 3], a: f32, b: f32| [0, 1, 2].map(|k| o[k] + u[k] * a + v[k] * b); - for (o, u, v, shade) in faces { - for i in 0..N { - for j in 0..N { - let (a0, a1, b0, b1) = (i as f32 / N as f32, (i + 1) as f32 / N as f32, j as f32 / N as f32, (j + 1) as f32 / N as f32); - let m = point(o, u, v, (a0 + a1) / 2.0, (b0 + b1) / 2.0); - let r = m.iter().map(|x| (0.5 - x) * (0.5 - x)).sum::<f32>().sqrt(); - let band = RADII.iter().filter(|&&rad| r < rad).count(); - let (cr, cg, cb) = FRINGE.get(band).copied().unwrap_or(FRINGE[0]); - let k = 1.0 - shade; - let col = Color32::from_rgb((cr as f32 * k) as u8, (cg as f32 * k) as u8, (cb as f32 * k) as u8); - let quad = vec![at(point(o, u, v, a0, b0)), at(point(o, u, v, a1, b0)), at(point(o, u, v, a1, b1)), at(point(o, u, v, a0, b1))]; - // A hairline in the cell's own colour closes the seams between neighbouring cells. - p.add(egui::Shape::convex_polygon(quad, col, Stroke::new(0.5, col))); - } - } - } -} +// OneBSpace (OneCAD Simulation): upstream's drawn fringe-cube mark (`mark`, after +// `assets/app-icon/icon-small.svg`) is replaced by a painted text wordmark, so the bar names +// the fork in every width variant (a narrow bar loses the menus, not the app's own name). +pub const APP_NAME: &str = "OneCAD Simulation"; /// Where the title bar's parts go. #[derive(Clone, Copy, Debug, PartialEq)] pub struct BarLayout { - /// The mark's centre, and where the app's name starts (none when compact). + /// The wordmark's left anchor ("OneCAD Simulation", painted text). pub mark: egui::Pos2, - pub name: Option<egui::Pos2>, - /// File, Save, Undo, Redo: after the mark, at the left. + /// File, Save, Undo, Redo: after the wordmark, at the left. pub quick: [Rect; 4], /// Solve, then Search, Theme and Help: at the right end, before the version. pub solve: Rect, @@ -112,19 +80,23 @@ pub struct BarLayout { pub tab_room: (f32, f32), /// The version's right edge. pub version_right: f32, - /// Too narrow for labels: no name, and Solve without its word. + /// Too narrow for menus: Solve without its word (the wordmark still shows). pub compact: bool, } /// The title bar's layout in `bar`. `traffic_lights`: the macOS window buttons sit over its left /// end (an integrated title bar out of full screen, where there are none). `captions`: the width -/// of the custom caption buttons at its right end; `version_w`: the version text's width. -pub fn bar_layout(bar: Rect, traffic_lights: bool, captions: f32, version_w: f32) -> BarLayout { +/// of the custom caption buttons at its right end; `version_w`: the version text's width; +/// `name_w`: the wordmark's width (OneBSpace (OneCAD Simulation): the quick actions start after +/// the wordmark, in every width variant). +pub fn bar_layout(bar: Rect, traffic_lights: bool, captions: f32, version_w: f32, name_w: f32) -> BarLayout { let left = bar.left() + if traffic_lights { crate::titlebar::TRAFFIC_LIGHTS } else { 0.0 }; let compact = bar.right() - left < 760.0; let cy = bar.center().y; let button = |x: f32| Rect::from_center_size(pos2(x + BUTTON / 2.0, cy), Vec2::splat(BUTTON)); - let x0 = left + if compact { 44.0 } else { 132.0 }; + // OneBSpace (OneCAD Simulation): the quick actions start after the wordmark in compact + // layouts too (upstream's compact bar dropped the name and started at the bare mark). + let x0 = left + 14.0 + name_w + 22.0; let quick = [0.0, 1.0, 2.0, 3.0].map(|i| button(x0 + i * STRIDE)); let version_right = bar.right() - 12.0 - captions; let tools_end = version_right - version_w - 14.0; @@ -132,8 +104,7 @@ pub fn bar_layout(bar: Rect, traffic_lights: bool, captions: f32, version_w: f32 let solve_w = if compact { 30.0 } else { 74.0 }; let solve = Rect::from_min_size(pos2(tools[0].left() - 10.0 - solve_w, cy - 12.0), vec2(solve_w, 24.0)); BarLayout { - mark: pos2(left + 20.0, cy), - name: (!compact).then(|| pos2(left + 36.0, cy)), + mark: pos2(left + 14.0, cy), quick, solve, tools, @@ -161,11 +132,11 @@ pub fn app_bar(app: &mut ModelApp, ui: &mut egui::Ui) { let captions = if app.custom_titlebar { crate::titlebar::WIDTH } else { 0.0 }; let version = format!("v{}", crate::VERSION); let version_w = ui.painter().layout_no_wrap(version.clone(), FontId::proportional(11.0), t.text_dim).size().x; - let lay = bar_layout(r, app.integrated_titlebar && !fullscreen(ui.ctx()), captions, version_w); - mark(ui.painter(), lay.mark); - if let Some(at) = lay.name { - ui.painter().text(at, Align2::LEFT_CENTER, "FieldCraft", FontId::proportional(14.0), t.app_bar_text); - } + // OneBSpace (OneCAD Simulation): the wordmark is measured so the quick actions clear it. + let name_w = ui.painter().layout_no_wrap(APP_NAME.to_string(), FontId::proportional(14.0), t.app_bar_text).size().x; + let lay = bar_layout(r, app.integrated_titlebar && !fullscreen(ui.ctx()), captions, version_w, name_w); + // OneBSpace (OneCAD Simulation): painted wordmark instead of the drawn mark + name. + ui.painter().text(lay.mark, Align2::LEFT_CENTER, APP_NAME, FontId::proportional(14.0), t.app_bar_text); let (undo, redo) = app.session.undo_depth(); let busy = app.busy().is_some(); let file_open = app.ui.menu.as_deref() == Some("file"); @@ -336,30 +307,16 @@ fn help_menu(app: &mut ModelApp, ui: &mut egui::Ui) { ui.label("Left drag orbits (or pans or zooms: the navigation bar), right or middle drag pans, the wheel zooms, F or a double click fits."); ui.label(format!("S or {} searches every command; the command line at the bottom runs `id {{json}}`.", shortcut("K"))); ui.separator(); - let report = ui - .button("Report a Bug…") - .on_hover_text("Draft a GitHub issue with the version, the OS and the last error; nothing is sent until you submit it") - .clicked(); - let (mut check, mut reinstall) = (false, false); - if app.updates_available() { - check = - ui.button("Check for Updates").on_hover_text("Ask GitHub Releases whether a newer FieldCraft is published (app.update.check)").clicked(); - reinstall = ui - .button("Reinstall FieldCraft…") - .on_hover_text("Download this version again, verify it and swap it in, to repair a damaged install") - .clicked(); - } + // OneBSpace (OneCAD Simulation): upstream's "Report a Bug…", "Check for Updates" and + // "Reinstall FieldCraft…" items are gone — nothing here reaches GitHub or an update host. + // A report is drafted locally ("Report It…" after a crash, Help › Crash Reports) and copied + // out by hand; the version label names the fork. let crashes = ui.button("Crash Reports…").on_hover_text("The crash reports saved on this computer: report, copy or delete them").clicked(); let settings = ui.button("Settings…").on_hover_text("Privacy and updates").clicked(); - ui.label(egui::RichText::new(format!("FieldCraft {}", crate::VERSION)).color(t.text_dim)); - if report { - app.report_bug(None); - } else if crashes { + // OneBSpace (OneCAD Simulation): the version label carries the fork's name. + ui.label(egui::RichText::new(format!("{} {}", APP_NAME, crate::VERSION)).color(t.text_dim)); + if crashes { app.open_crash_reports(); - } else if check { - app.check_for_updates(); - } else if reinstall { - app.reinstall(); } else if settings { app.open_settings(); } @@ -377,13 +334,16 @@ mod tests { /// at the very left in full screen (where there are none). #[test] fn the_title_bar_keeps_solve_right_and_drops_the_traffic_light_inset_in_full_screen() { + // OneBSpace (OneCAD Simulation): the layout takes the wordmark's width; a plausible + // measured value stands in for the font here. + let name_w = 120.0; let bar = Rect::from_min_size(egui::Pos2::ZERO, vec2(1400.0, HEIGHT)); - let windowed = bar_layout(bar, true, 0.0, 30.0); - let full = bar_layout(bar, false, 0.0, 30.0); + let windowed = bar_layout(bar, true, 0.0, 30.0, name_w); + let full = bar_layout(bar, false, 0.0, 30.0, name_w); assert_eq!(windowed.mark.x - full.mark.x, crate::titlebar::TRAFFIC_LIGHTS); - assert!(full.mark.x < 30.0 && full.quick[0].left() < 150.0, "{full:?}"); + assert!(full.mark.x < 30.0 && full.quick[0].left() < 200.0, "{full:?}"); for l in [windowed, full] { - // Left to right: mark, quick actions, (tab), Solve, search, theme, help, version. + // Left to right: wordmark, quick actions, (tab), Solve, search, theme, help, version. assert!(l.quick.windows(2).all(|w| w[0].right() <= w[1].left())); assert!(l.quick[3].right() < l.tab_room.0 && l.tab_room.1 < l.solve.left()); assert!(l.solve.right() <= l.tools[0].left() && l.tools.windows(2).all(|w| w[0].right() <= w[1].left())); @@ -392,10 +352,13 @@ mod tests { } // The right group does not move with full screen; custom caption buttons push it left. assert_eq!(windowed.solve, full.solve); - let captions = bar_layout(bar, false, crate::titlebar::WIDTH, 30.0); + let captions = bar_layout(bar, false, crate::titlebar::WIDTH, 30.0, name_w); assert!((full.tools[2].right() - captions.tools[2].right() - crate::titlebar::WIDTH).abs() < 0.01); - // Narrow: compact, still in order. - let narrow = bar_layout(Rect::from_min_size(egui::Pos2::ZERO, vec2(700.0, HEIGHT)), true, 0.0, 30.0); - assert!(narrow.compact && narrow.name.is_none() && narrow.quick[3].right() < narrow.solve.left()); + // Narrow: compact, the wordmark still first and the quick actions after it, in order. + let narrow = bar_layout(Rect::from_min_size(egui::Pos2::ZERO, vec2(700.0, HEIGHT)), true, 0.0, 30.0, name_w); + assert!(narrow.compact && narrow.quick[3].right() < narrow.solve.left(), "{narrow:?}"); + // OneBSpace (OneCAD Simulation): every width shows the wordmark, and the quick actions + // start after it (they no longer sit on the bare mark in the compact bar). + assert!(narrow.quick[0].left() >= narrow.mark.x + name_w, "{narrow:?}"); } } diff --git a/crates/ui-egui/src/navigation.rs b/crates/ui-egui/src/navigation.rs index 2637a9b..bf7397a 100644 --- a/crates/ui-egui/src/navigation.rs +++ b/crates/ui-egui/src/navigation.rs @@ -77,7 +77,9 @@ pub const DEFAULT_PRESET: &str = "fieldcraft"; pub const NAV_PRESETS: [NavPreset; 7] = [ NavPreset { id: DEFAULT_PRESET, - label: "FieldCraft", + // OneBSpace (OneCAD Simulation): the preset's label names the fork (its `id`, which + // preferences store, stays upstream). + label: "OneCAD Simulation", help: "Left drag does the navigation bar's mode (orbit, pan or zoom); right, middle or Shift+left drag pans", reverse_zoom: false, bindings: &[bind(Left, NavKeys::SHIFT, Pan), bind(Right, NavKeys::NONE, Pan), bind(Middle, NavKeys::NONE, Pan)], diff --git a/crates/ui-egui/src/privacy.rs b/crates/ui-egui/src/privacy.rs index 112e19f..ae12c26 100644 --- a/crates/ui-egui/src/privacy.rs +++ b/crates/ui-egui/src/privacy.rs @@ -12,10 +12,12 @@ use fieldcraft_engine::usage::{self, Event, Identity, Origin}; use crate::ModelApp; use crate::files::Prompt; -/// What is sent, event by event. +/// What is sent, event by event. (OneBSpace (OneCAD Simulation): upstream's PRIVACY_URL linked +/// out to github.com/tangency-labs/fieldcraft; the constant stays for reference but the UI no +/// longer renders it as a link or opens it — nothing here browses anywhere.) pub const PRIVACY_URL: &str = "https://github.com/tangency-labs/fieldcraft/blob/main/docs/privacy.md"; -/// The question, as the first run asks it. -pub const QUESTION: &str = "Help improve FieldCraft by sharing anonymous usage: which tools you use, nothing from your models."; +/// The question, as the first run asks it. (OneBSpace (OneCAD Simulation): fork name.) +pub const QUESTION: &str = "Help improve OneCAD Simulation by sharing anonymous usage: which tools you use, nothing from your models."; const DETAIL: &str = "Counted: the commands you run (their names, how long they took, whether they failed), the steps from a design to results, \ the samples you open, and the version, OS and a random id for this install. Never sent: file names or paths, geometry, model \ contents, parameter values or messages."; @@ -143,14 +145,17 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { let t = crate::theme::Tokens::get(app.ui.dark); match app.prompt { Some(Prompt::Consent) => { - let (mut share, mut decline, mut link, mut updates) = (false, false, false, None); - crate::frame::window(ctx, "Help Improve FieldCraft", crate::frame::Width::Normal).id(egui::Id::new("fc_consent")).show(ctx, |ui| { + // OneBSpace (OneCAD Simulation): the privacy note is plain text — the upstream + // GitHub link (PRIVACY_URL) is not rendered as a link and never opened. + let (mut share, mut decline, mut updates) = (false, false, None); + // OneBSpace (OneCAD Simulation): the fork's name in the dialog title. + crate::frame::window(ctx, "Help Improve OneCAD Simulation", crate::frame::Width::Normal).id(egui::Id::new("fc_consent")).show(ctx, |ui| { ui.label(QUESTION); ui.add_space(4.0); ui.label(RichText::new(DETAIL).color(t.text_dim).size(11.0)); ui.add_space(2.0); ui.label(RichText::new("You can change this any time in Help › Settings.").color(t.text_dim).size(11.0)); - link = ui.link("What is sent (docs/privacy.md)").on_hover_text(PRIVACY_URL).clicked(); + ui.label(RichText::new("What is sent: docs/privacy.md in the repository.").color(t.text_dim).size(11.0)); if app.updates_available() { ui.add_space(4.0); updates = update_check(ui, &t, app.prefs.update_check); @@ -161,9 +166,6 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { decline = ui.button("Don't Share").clicked(); }); }); - if link { - app.open_link(ctx, PRIVACY_URL); - } if let Some(on) = updates { app.set_update_prefs(on, None); } @@ -176,15 +178,20 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { Some(Prompt::Settings) => { let available = app.usage_available(); let (mut sharing, mut automation) = (app.prefs.usage_sharing == Some(true), app.prefs.usage_automation); - let (mut close, mut link, mut updates, mut unskip, mut check) = (false, false, None, false, false); + // OneBSpace (OneCAD Simulation): the privacy note is plain text — no link, no + // browser. The dialog never opens PRIVACY_URL. + let (mut close, mut updates, mut unskip, mut check) = (false, None, false, false); crate::frame::window(ctx, "Settings", crate::frame::Width::Normal).id(egui::Id::new("fc_settings")).show(ctx, |ui| { if app.updates_available() { crate::frame::menu_heading(ui, &t, "UPDATES"); updates = update_check(ui, &t, app.prefs.update_check); ui.horizontal(|ui| { - check = ui.button("Check Now").on_hover_text("Help › Check for Updates").clicked(); + // OneBSpace (OneCAD Simulation): the tooltip no longer points at Help › + // Check for Updates (that menu item was removed with the fork's rebrand). + check = ui.button("Check Now").on_hover_text("Ask GitHub Releases for the latest version now").clicked(); if !app.prefs.update_skip.is_empty() { - ui.label(RichText::new(format!("Skipping FieldCraft {}", app.prefs.update_skip)).color(t.text_dim).size(11.0)); + // OneBSpace (OneCAD Simulation): the fork's name in the skip note. + ui.label(RichText::new(format!("Skipping OneCAD Simulation {}", app.prefs.update_skip)).color(t.text_dim).size(11.0)); unskip = ui.small_button("Offer It Again").clicked(); } }); @@ -207,11 +214,13 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { } ui.label(RichText::new(DETAIL).color(t.text_dim).size(11.0)); ui.label( - RichText::new("Crash reports and the log stay on this computer; Help › Report a Bug sends only what you submit.") + // OneBSpace (OneCAD Simulation): the report flow is local-only now (a draft + // to copy), so the note no longer promises a GitHub submission. + RichText::new("Crash reports and the log stay on this computer; a report is drafted here and copied out — nothing is sent anywhere.") .color(t.text_dim) .size(11.0), ); - link = ui.link("What is sent (docs/privacy.md)").on_hover_text(PRIVACY_URL).clicked(); + ui.label(RichText::new("What is sent: docs/privacy.md in the repository.").color(t.text_dim).size(11.0)); ui.add_space(6.0); close = ui.button("Close").clicked(); }); @@ -224,9 +233,6 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { if check { app.check_for_updates(); } - if link { - app.open_link(ctx, PRIVACY_URL); - } if close || ctx.input(|i| i.key_pressed(egui::Key::Escape)) { app.prompt = None; } @@ -241,11 +247,13 @@ fn update_check(ui: &mut egui::Ui, t: &crate::theme::Tokens, on: bool) -> Option let changed = ui .checkbox(&mut checked, "Check for updates automatically") .on_hover_text( - "At start-up, at most once a day, FieldCraft asks GitHub Releases for the latest version. Nothing installs until you choose Install.", + // OneBSpace (OneCAD Simulation): the fork's name in the tooltip (desktop-only check). + "At start-up, at most once a day, OneCAD Simulation asks GitHub Releases for the latest version. Nothing installs until you choose Install.", ) .changed(); ui.label( - RichText::new("The check sends only the request (your IP address and the FieldCraft version reach GitHub); off means no check.") + // OneBSpace (OneCAD Simulation): the fork's name in the note. + RichText::new("The check sends only the request (your IP address and the OneCAD Simulation version reach GitHub); off means no check.") .color(t.text_dim) .size(11.0), ); diff --git a/crates/ui-egui/src/report.rs b/crates/ui-egui/src/report.rs index 9acbe79..9c062e5 100644 --- a/crates/ui-egui/src/report.rs +++ b/crates/ui-egui/src/report.rs @@ -1,13 +1,13 @@ -//! Help › Report a Bug, and the question the window asks after a crash ("FieldCraft closed -//! unexpectedly — Report it"). +//! Help › Crash Reports, "Report It…" after a crash ("OneCAD Simulation closed unexpectedly — +//! Report it"), and the Report a Bug form they open. //! -//! The form shows exactly what the GitHub issue form will be filled with -//! ([`fieldcraft_engine::bug_report`]): the version, the OS, what happened (the last error by -//! default) and, after a crash, where it happened. **Share my session** adds the commands that -//! built the model, **Include the model file** the model as well. Nothing leaves the computer -//! until the user clicks **Open GitHub Issue**, which opens the filled form in their browser (they -//! submit it there, or not); files too big for the link are saved to a folder to attach from, and -//! a long session is also put on the clipboard. +// OneBSpace (OneCAD Simulation): upstream opened the filled GitHub issue form in the browser; +// the fork's report flow is local-only — the form shows exactly what the draft holds +// ([`fieldcraft_engine::bug_report`]): the version, the OS, what happened (the last error by +// default) and, after a crash, where it happened. **Share my session** adds the commands that +// built the model, **Include the model file** the model as well. **Copy report** puts it all on +// the clipboard (nothing opens, nothing is sent); attachments are saved to a local folder to +// attach from wherever the user files their reports. use egui::RichText; use fieldcraft_engine::bug_report::{self, Draft, Input}; @@ -169,37 +169,29 @@ impl ModelApp { } } - /// Open the draft in the browser: attachments saved to a folder of their own, the session on - /// the clipboard when it is too long for the link. - fn send_report(&mut self, ctx: &egui::Context, draft: &Draft) { - let mut saved = None; - if !draft.attachments.is_empty() { + // OneBSpace (OneCAD Simulation): the report never leaves the workspace — no GitHub issue + // form is opened (upstream opened the draft's ISSUE_URL). The draft's text goes to the + // clipboard and any attachments stay in the local bug-reports folder to attach by hand. + fn copy_report(&mut self, ctx: &egui::Context, draft: &Draft) { + let mut text = draft.title.clone(); + for (k, v) in &draft.fields { + if !v.is_empty() { + text.push_str(&format!("\n\n{k}:\n{v}")); + } + } + if let Some(session) = &draft.clipboard { + text.push_str(&format!("\n\nsession:\n{session}")); + } + ctx.copy_text(text); + let note = if draft.attachments.is_empty() { + "Report copied to the clipboard — paste it into your own issue tracker.".to_string() + } else { match bug_report::save_attachments(draft) { - Ok(dir) => saved = Some(dir), - Err(e) => { - self.set_status(format!("Report a Bug: could not save the files to attach: {e}"), true); - return; - } + Ok(dir) => format!("Report copied to the clipboard: attach the files in {}.", dir.display()), + Err(e) => format!("Report copied to the clipboard (the files to attach could not be saved: {e})."), } - } - if let Some(text) = &draft.clipboard { - ctx.copy_text(text.clone()); - } - match &self.services.open_url { - Some(open) => { - if let Err(e) = open(&draft.url) { - self.set_status(format!("Report a Bug: could not open the browser: {e}"), true); - return; - } - } - None => ctx.open_url(egui::OpenUrl::new_tab(draft.url.clone())), - } - log::info!("bug report opened in the browser ({} bytes, {} attachment(s))", draft.url.len(), draft.attachments.len()); - let text = match saved { - Some(dir) => format!("The issue form opened in your browser: attach the files in {} and submit it there.", dir.display()), - None => "The issue form opened in your browser: review it and submit it there.".to_string(), }; - self.set_status(text, false); + self.set_status(note, false); self.prompt = None; self.report = None; } @@ -226,10 +218,11 @@ fn size(bytes: usize) -> String { } fn kind_label(kind: &str) -> &'static str { + // OneBSpace (OneCAD Simulation): the fork's name in the crash headings. match kind { - "unclean_exit" => "FieldCraft closed unexpectedly", + "unclean_exit" => "OneCAD Simulation closed unexpectedly", "command_panic" => "A command hit an internal error", - _ => "FieldCraft hit an internal error", + _ => "OneCAD Simulation hit an internal error", } } @@ -245,8 +238,9 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { let (mut report, mut close) = (false, false); crate::frame::window(ctx, kind_label(&first.kind), crate::frame::Width::Normal).id(egui::Id::new("fc_crashed")).show(ctx, |ui| { ui.label(match first.kind.as_str() { - "unclean_exit" => "FieldCraft closed unexpectedly the last time it ran.", - _ => "FieldCraft hit an internal error the last time it ran.", + // OneBSpace (OneCAD Simulation): the fork's name in the crash question. + "unclean_exit" => "OneCAD Simulation closed unexpectedly the last time it ran.", + _ => "OneCAD Simulation hit an internal error the last time it ran.", }); ui.label(RichText::new(&first.message).color(t.text_dim)); if reports.len() > 1 { @@ -254,8 +248,10 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { } ui.add_space(4.0); ui.label( + // OneBSpace (OneCAD Simulation): reporting drafts locally — no GitHub issue + // is opened; the user copies the report into their own tracker. RichText::new( - "A crash report was saved on this computer. Reporting it opens a GitHub issue you review first; nothing is sent until you submit it.", + "A crash report was saved on this computer. Reporting it drafts a report that stays in the workspace: copy it into your own issue tracker; nothing is sent anywhere.", ) .color(t.text_dim), ); @@ -285,7 +281,9 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { ui.label("No crash reports are saved on this computer."); } else { ui.label( - RichText::new("Saved on this computer, newest first. Reporting one opens a GitHub issue you review first; nothing is sent until you submit it.") + // OneBSpace (OneCAD Simulation): reporting drafts locally — no GitHub + // issue is opened; the report is copied out by hand. + RichText::new("Saved on this computer, newest first. Reporting one drafts a report that stays in the workspace: copy it into your own issue tracker.") .color(t.text_dim), ); ui.add_space(4.0); @@ -344,14 +342,14 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { app.prompt = None; return; }; - let (mut send, mut close) = (false, false); + let (mut copy, mut close) = (false, false); let commands = form.input.commands.len(); crate::frame::window(ctx, "Report a Bug", crate::frame::Width::Wide).id(egui::Id::new("fc_report_bug")).show(ctx, |ui| { ui.label( - RichText::new( - "This opens a GitHub issue in your browser, filled in with what is shown below. Nothing is sent until you submit it there.", - ) - .color(t.text_dim), + // OneBSpace (OneCAD Simulation): the report stays in the workspace — it is + // copied to the clipboard, never opened as a GitHub issue in the browser. + RichText::new("Your report stays in the workspace: copy it and paste it into your own issue tracker. Nothing is sent anywhere.") + .color(t.text_dim), ); if let Some(p) = &form.problem { ui.label(RichText::new(p).color(t.error)); @@ -386,11 +384,12 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { let draft = form.draft().clone(); ui.add_space(6.0); ui.horizontal(|ui| { - send = ui.button("Open GitHub Issue").clicked(); + // OneBSpace (OneCAD Simulation): "Copy report" instead of "Open GitHub Issue". + copy = ui.button("Copy report").clicked(); close = ui.button("Cancel").clicked(); }); ui.add_space(4.0); - egui::CollapsingHeader::new("What is sent").id_salt("fc_report_sent").default_open(true).show(ui, |ui| { + egui::CollapsingHeader::new("What is in the report").id_salt("fc_report_sent").default_open(true).show(ui, |ui| { egui::ScrollArea::vertical().max_height(180.0).show(ui, |ui| { ui.label(RichText::new(format!("Title: {}", draft.title)).monospace().size(11.0)); for (k, v) in &draft.fields { @@ -403,15 +402,17 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { ui.label(RichText::new(format!("Attach {} ({}): {}", a.name, size(a.bytes.len()), a.what)).size(11.0).color(t.accent)); } if draft.clipboard.is_some() { - ui.label(RichText::new("The session goes on the clipboard too, to paste.").size(11.0).color(t.text_dim)); + // OneBSpace (OneCAD Simulation): the session is copied with the report. + ui.label(RichText::new("The session is copied with the report.").size(11.0).color(t.text_dim)); } }); }); }); let draft = form.draft().clone(); app.report = Some(form); - if send { - app.send_report(ctx, &draft); + // OneBSpace (OneCAD Simulation): the copied report never touches the network. + if copy { + app.copy_report(ctx, &draft); } else if close || ctx.input(|i| i.key_pressed(egui::Key::Escape)) { app.prompt = None; app.report = None; diff --git a/crates/ui-egui/src/updates.rs b/crates/ui-egui/src/updates.rs index f55cdac..fa5a868 100644 --- a/crates/ui-egui/src/updates.rs +++ b/crates/ui-egui/src/updates.rs @@ -123,9 +123,9 @@ impl ModelApp { self.set_status(format!("Cannot reinstall: {why}"), true); return; } - u.busy = Some(format!("Downloading FieldCraft {}…", crate::VERSION)); + u.busy = Some(format!("Downloading OneCAD Simulation {}…", crate::VERSION)); // OneBSpace (OneCAD Simulation): fork name in the status (u.host.start)(Job::Reinstall); - self.set_status(format!("Downloading FieldCraft {} to reinstall it…", crate::VERSION), false); + self.set_status(format!("Downloading OneCAD Simulation {} to reinstall it…", crate::VERSION), false); // OneBSpace (OneCAD Simulation) } /// The notice's Install: download and verify, then ask to restart. A copy that cannot @@ -133,15 +133,16 @@ impl ModelApp { pub fn install_update(&mut self, ctx: &egui::Context) { let Some(u) = &mut self.updates else { return }; let Some(release) = u.available.clone() else { return }; - let blocked = u.host.unsupported.clone().or_else(|| (!release.signed()).then(|| format!("FieldCraft {} is not signed", release.version))); + // OneBSpace (OneCAD Simulation): the fork's name in the not-signed status. + let blocked = u.host.unsupported.clone().or_else(|| (!release.signed()).then(|| format!("OneCAD Simulation {} is not signed", release.version))); if let Some(why) = blocked { self.set_status(format!("{why}: opening the download page"), true); self.open_link(ctx, &release.url); return; } - u.busy = Some(format!("Downloading FieldCraft {}…", release.version)); + u.busy = Some(format!("Downloading OneCAD Simulation {}…", release.version)); // OneBSpace (OneCAD Simulation) (u.host.start)(Job::Stage(release.clone())); - self.set_status(format!("Downloading FieldCraft {}…", release.version), false); + self.set_status(format!("Downloading OneCAD Simulation {}…", release.version), false); // OneBSpace (OneCAD Simulation) } /// Skip the offered version: the automatic check no longer offers it. @@ -178,7 +179,7 @@ impl ModelApp { && let Some((s, Finish::Swap(_))) = &u.staged { let v = s.version.to_string(); - self.set_status(format!("FieldCraft {v} installs when you quit"), false); + self.set_status(format!("OneCAD Simulation {v} installs when you quit"), false); // OneBSpace (OneCAD Simulation) } return; } @@ -234,14 +235,16 @@ impl ModelApp { let v = check.latest.version.to_string(); u.available = Some(check.latest); if manual { - self.set_status(format!("FieldCraft {v} is available"), false); + // OneBSpace (OneCAD Simulation): the fork's name in the status. + self.set_status(format!("OneCAD Simulation {v} is available"), false); } } Ok(check) => { // Nothing newer (or skipped): a notice from an earlier check goes. u.available = None; if manual { - self.set_status(format!("FieldCraft {} is up to date", check.current), false); + // OneBSpace (OneCAD Simulation): the fork's name in the status. + self.set_status(format!("OneCAD Simulation {} is up to date", check.current), false); } } Err(e) if manual => self.set_status(format!("Could not check for updates: {e}"), true), @@ -310,7 +313,8 @@ pub fn notice(app: &mut ModelApp, ui: &mut egui::Ui) { if ui.add(egui::Link::new(RichText::new("Reload to update").size(11.5))).on_hover_text(tip).clicked() { reload(); } - ui.label(RichText::new("A new version of FieldCraft is available —").size(11.5).color(t.text)); + // OneBSpace (OneCAD Simulation): the fork's name in the status-bar notice. + ui.label(RichText::new("A new version of OneCAD Simulation is available —").size(11.5).color(t.text)); ui.separator(); return; } @@ -328,7 +332,8 @@ pub fn notice(app: &mut ModelApp, ui: &mut egui::Ui) { let install = ui.add(egui::Link::new(small("Install"))).on_hover_text("Download, verify and install it; you choose when to restart").clicked(); ui.label(small("·").color(t.text_dim)); let notes = ui.add(egui::Link::new(small("What's new"))).on_hover_text(release.url.as_str()).clicked(); - ui.label(small(&format!("FieldCraft {} is available —", release.version)).color(t.text)); + // OneBSpace (OneCAD Simulation): the fork's name in the status-bar notice. + ui.label(small(&format!("OneCAD Simulation {} is available —", release.version)).color(t.text)); ui.separator(); if notes { app.open_link(ui.ctx(), &release.url); @@ -353,12 +358,13 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { }; let reinstall = staged.version.to_string() == crate::VERSION; let (mut restart, mut later, mut open) = (false, false, false); - crate::frame::window(ctx, "Update FieldCraft", crate::frame::Width::Normal).id(egui::Id::new("fc_update")).show(ctx, |ui| match &finish { + // OneBSpace (OneCAD Simulation): the fork's name in the window title. + crate::frame::window(ctx, "Update OneCAD Simulation", crate::frame::Width::Normal).id(egui::Id::new("fc_update")).show(ctx, |ui| match &finish { Finish::Swap(_) => { ui.label(if reinstall { - format!("FieldCraft {} was downloaded again and verified. Restart to reinstall it?", staged.version) + format!("OneCAD Simulation {} was downloaded again and verified. Restart to reinstall it?", staged.version) } else { - format!("FieldCraft {} is downloaded and verified. Restart now to finish installing it?", staged.version) + format!("OneCAD Simulation {} is downloaded and verified. Restart now to finish installing it?", staged.version) }); ui.label( RichText::new(format!("It replaces {}. Unsaved changes are saved or asked about first.", staged.install.describe())) @@ -368,11 +374,11 @@ pub fn show(app: &mut ModelApp, ctx: &egui::Context) { ui.add_space(6.0); ui.horizontal(|ui| { restart = ui.button("Restart Now").clicked(); - later = ui.button("Later").on_hover_text("It installs when you quit FieldCraft").clicked(); + later = ui.button("Later").on_hover_text("It installs when you quit OneCAD Simulation").clicked(); // OneBSpace (OneCAD Simulation) }); } Finish::Package { file, command } => { - ui.label(format!("FieldCraft {} is downloaded and verified:", staged.version)); + ui.label(format!("OneCAD Simulation {} is downloaded and verified:", staged.version)); // OneBSpace (OneCAD Simulation) ui.label(RichText::new(file.display().to_string()).monospace().size(11.0)); ui.label("Install it with your system's package manager:"); let mut text = command.clone(); @@ -516,7 +522,7 @@ mod tests { tx.send(Event::Checked { manual: true, result: Ok(Check { current: current.clone(), latest: release(crate::VERSION) }) }).unwrap(); a.poll_updates(&ctx); - assert_eq!(a.status.as_ref().map(|s| s.text.clone()), Some(format!("FieldCraft {} is up to date", crate::VERSION))); + assert_eq!(a.status.as_ref().map(|s| s.text.clone()), Some(format!("OneCAD Simulation {} is up to date", crate::VERSION))); // OneBSpace (OneCAD Simulation) assert_eq!(a.update_offered(), None, "the earlier offer goes"); tx.send(Event::Checked { manual: false, result: Err("offline".into()) }).unwrap(); a.status = None;