forked from 1b-agent/fieldcraft-upstream
[IMP] OneCAD Simulation rebrand: OneCAD Simulation wordmark + app bar, no external links (docs/GitHub/updates removed, local report copy), all visible strings OneCAD Simulation, REBRAND.md
This commit is contained in:
1 parent
8201f9a954
commit
f8c0e8500a
11 files changed
+220
-177
No files matched your search
+48
@@ -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 | `<title>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.
|
||||
@@ -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");
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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: &[],
|
||||
|
||||
@@ -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: &[],
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:?}");
|
||||
}
|
||||
}
|
||||
@@ -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)],
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -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,13 +342,13 @@ 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.",
|
||||
)
|
||||
// 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 {
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user