forked from 1b-agent/fieldcraft-upstream
Web: offer Reload to update when a new deployment is out (#231)
Every half hour the page fetches its own address past the browser's cache; when it loads another content-hashed build of the app than the running one, the status bar offers "Reload to update" (the page's unsaved-changes question still guards the reload). Rust only, no service worker: the browser build has no other update path and none of the desktop's download code. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
7dd50a3ca4
commit
93b2ae343c
6 files changed
+145
-3
No files matched your search
@@ -391,6 +391,8 @@ pub struct ModelApp {
|
||||
consent_asked: bool,
|
||||
/// Checking for and installing updates, when this run may ([`updates`]).
|
||||
updates: Option<updates::State>,
|
||||
/// The web app: a new deployment is out, and this reloads the page into it.
|
||||
reload: Option<Box<dyn Fn()>>,
|
||||
/// The setup progress the browser marks, and what it was worked out for.
|
||||
setup: (Option<(u64, u64, bool, bool)>, std::sync::Arc<Vec<fieldcraft_engine::progress::StageState>>),
|
||||
/// The file opening in the background, and files waiting to open after it.
|
||||
@@ -481,6 +483,7 @@ impl ModelApp {
|
||||
usage: None,
|
||||
consent_asked: false,
|
||||
updates: None,
|
||||
reload: None,
|
||||
setup: (None, std::sync::Arc::default()),
|
||||
loading: None,
|
||||
queued: std::collections::VecDeque::new(),
|
||||
|
||||
@@ -276,6 +276,16 @@ impl ModelApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// The web app: a new deployment is out; the status bar offers to reload into it.
|
||||
pub fn offer_reload(&mut self, reload: Box<dyn Fn()>) {
|
||||
self.reload = Some(reload);
|
||||
}
|
||||
|
||||
/// Whether the status bar offers to reload into a new deployment.
|
||||
pub fn reload_offered(&self) -> bool {
|
||||
self.reload.is_some()
|
||||
}
|
||||
|
||||
/// For the control channel's `ui.inspect`.
|
||||
pub fn update_json(&self) -> serde_json::Value {
|
||||
let Some(u) = &self.updates else { return serde_json::Value::Null };
|
||||
@@ -291,9 +301,19 @@ impl ModelApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// The status bar's notice: an update offered, or one downloading.
|
||||
/// The status bar's notice: an update offered, or one downloading; in the browser, a new
|
||||
/// deployment to reload into.
|
||||
pub fn notice(app: &mut ModelApp, ui: &mut egui::Ui) {
|
||||
let t = crate::theme::Tokens::get(app.ui.dark);
|
||||
if let Some(reload) = &app.reload {
|
||||
let tip = if app.has_unsaved_work() { "Reloads the page; you are asked about the unsaved changes first" } else { "Reloads the page" };
|
||||
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));
|
||||
ui.separator();
|
||||
return;
|
||||
}
|
||||
let Some(u) = &app.updates else { return };
|
||||
if let Some(busy) = &u.busy {
|
||||
ui.label(RichText::new(busy).size(11.5).color(t.text_dim));
|
||||
|
||||
Reference in new issue
Block a user