1.24.0: la versión nueva también llega con la app abierta todo el día

La app solo buscaba versión nueva al abrir: un equipo que la deja abierta de la mañana
a la noche se quedaba en la de la mañana (este PC seguía en la 1.20 con la 1.23
publicada, y Rellenar con IA no le llegaba). Ahora, cada hora, mira si hay una nueva
sin instalarla: la versión de la barra pasa a «Actualizar a vX» (en el color de la
marca) y avisa una vez por versión. Al pulsarlo instala, se reinicia y vuelve a abrir
las pestañas. No se reinicia sola en medio del trabajo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Este commit está contenido en:
Munka
2026-10-14 22:05:19 -05:00
padre ed4c0ed529
commit 4e27406e25
Se han modificado 7 ficheros con 77 adiciones y 5 borrados

Ver fichero

@@ -280,6 +280,12 @@ guardada como secret del repo (`TAURI_SIGNING_PRIVATE_KEY`). También se puede f
la comprobación con clic en la versión de la barra, o desde el menú ⋮ ▸ *Buscar la comprobación con clic en la versión de la barra, o desde el menú ⋮ ▸ *Buscar
actualización…*. actualización…*.
Al **abrir**, la app busca versión nueva y, si la hay, la instala y se reinicia sola. Con la
app **abierta** (desde la 1.24) mira cada hora sin instalar nada: si hay una nueva, la versión
de la barra pasa a **«Actualizar a vX»** (en el color de la marca) y avisa una vez. Al pulsarlo
instala, se reinicia y vuelve a abrir las pestañas. No se reinicia sola en medio del trabajo:
se perdería lo que una página no hubiera guardado.
> ⚠️ De ahí se sigue algo que conviene tener presente: **un commit en `main` no le > ⚠️ De ahí se sigue algo que conviene tener presente: **un commit en `main` no le
> llega a nadie**. Mientras no exista la etiqueta `vX.Y.Z`, el CI no construye nada y > llega a nadie**. Mientras no exista la etiqueta `vX.Y.Z`, el CI no construye nada y
> el updater no ve versión nueva. Y al revés: publicar una etiqueta **actualiza la app > el updater no ve versión nueva. Y al revés: publicar una etiqueta **actualiza la app

16
dist/index.html vendido
Ver fichero

@@ -333,6 +333,14 @@
border-radius: 13px; border-radius: 13px;
} }
#version:hover { color: var(--accent); } #version:hover { color: var(--accent); }
/* Hay una versión nueva publicada: el botón la ofrece (clic: instala y reinicia). */
#version.nueva {
color: #fff;
background: var(--accent);
font-weight: 600;
padding: 0 10px;
}
#version.nueva:hover { color: #fff; filter: brightness(1.1); }
/* ── Botones de ventana ────────────────────────────────────────────────────────── /* ── Botones de ventana ──────────────────────────────────────────────────────────
Solo en Windows: allí la ventana va SIN decoración, así que esta barra es la fila Solo en Windows: allí la ventana va SIN decoración, así que esta barra es la fila
del título (como Chrome) y el aspa del sistema no existe. Medidas y colores del del título (como Chrome) y el aspa del sistema no existe. Medidas y colores del
@@ -595,7 +603,13 @@
$pct.textContent = estado.zoom + "%"; $pct.textContent = estado.zoom + "%";
$pct.classList.toggle("activo", estado.zoom !== 100); $pct.classList.toggle("activo", estado.zoom !== 100);
$ver.textContent = estado.version ? "v" + estado.version : ""; // Con una versión nueva esperando, el botón la ofrece; si no, la versión de ahora.
const nueva = estado.actualizacion || null;
$ver.textContent = nueva ? "Actualizar a v" + nueva : estado.version ? "v" + estado.version : "";
$ver.classList.toggle("nueva", !!nueva);
$ver.title = nueva
? "Hay una versión nueva (" + nueva + "): clic para instalarla. La app se reinicia y vuelve a abrir tus pestañas."
: "Versión de la app · clic: buscar actualización";
// Tema: manda el de la APP (payload `dark`). Mientras Rust no sepa nada (null), // Tema: manda el de la APP (payload `dark`). Mientras Rust no sepa nada (null),
// no se pone clase y siguen las media queries del sistema como arranque en frío. // no se pone clase y siguen las media queries del sistema como arranque en frío.
if (typeof estado.dark === "boolean") { if (typeof estado.dark === "boolean") {

Ver fichero

@@ -1,6 +1,6 @@
{ {
"name": "labstream-desktop", "name": "labstream-desktop",
"version": "1.23.0", "version": "1.24.0",
"private": true, "private": true,
"description": "App de escritorio (Windows) que envuelve Labstream OS — cliente del servidor del NAS.", "description": "App de escritorio (Windows) que envuelve Labstream OS — cliente del servidor del NAS.",
"scripts": { "scripts": {

Ver fichero

@@ -2367,7 +2367,7 @@ dependencies = [
[[package]] [[package]]
name = "labstream-desktop" name = "labstream-desktop"
version = "1.23.0" version = "1.24.0"
dependencies = [ dependencies = [
"active-win-pos-rs", "active-win-pos-rs",
"device_query", "device_query",

Ver fichero

@@ -1,6 +1,6 @@
[package] [package]
name = "labstream-desktop" name = "labstream-desktop"
version = "1.23.0" version = "1.24.0"
description = "Cliente de escritorio de Labstream OS" description = "Cliente de escritorio de Labstream OS"
authors = ["Labstream SAS"] authors = ["Labstream SAS"]
edition = "2021" edition = "2021"

Ver fichero

@@ -704,6 +704,8 @@ fn broadcast<R: Runtime>(app: &AppHandle<R>) {
"tabs": tabs, "tabs": tabs,
"zoom": (ZOOM_STEPS[s.zoom_idx.min(ZOOM_STEPS.len()-1)] * 100.0).round() as u32, "zoom": (ZOOM_STEPS[s.zoom_idx.min(ZOOM_STEPS.len()-1)] * 100.0).round() as u32,
"version": app.package_info().version.to_string(), "version": app.package_info().version.to_string(),
// La versión nueva que ya está publicada y espera a que se pulse «Actualizar» (o null).
"actualizacion": version_pendiente(),
// En macOS la barra ocupa la fila del título (ventana con título en overlay) y // En macOS la barra ocupa la fila del título (ventana con título en overlay) y
// debe dejar libre el hueco del semáforo, que lo pinta el sistema. // debe dejar libre el hueco del semáforo, que lo pinta el sistema.
"mac": cfg!(target_os = "macos"), "mac": cfg!(target_os = "macos"),
@@ -1557,6 +1559,47 @@ fn show_main<R: Runtime>(app: &AppHandle<R>) {
} }
} }
// ── La versión nueva, también con la app abierta todo el día (1.24, 14-oct-2026) ──
// Al abrir, la app busca versión nueva y, si hay, la instala y se reinicia (antes de que nadie
// trabaje). Pero solo al abrir: un equipo que deja la app abierta de la mañana a la noche se
// quedaba en la versión de la mañana (este PC seguía en la 1.20 con la 1.23 publicada, y Rellenar
// con IA no le llegaba). Ahora, cada hora, mira si hay una nueva SIN instalarla —reiniciar en
// medio del trabajo perdería lo que no se guardó en una página—: la barra cambia la versión por
// «Actualizar a vX» (el mismo botón de siempre: instala y reinicia, y las pestañas vuelven) y
// avisa una vez por versión.
const BUSCAR_CADA: Duration = Duration::from_secs(60 * 60);
static PENDIENTE: Mutex<Option<String>> = Mutex::new(None);
fn version_pendiente() -> Option<String> {
PENDIENTE.lock().ok().and_then(|p| p.clone())
}
#[cfg(desktop)]
async fn buscar_sin_instalar(handle: tauri::AppHandle) {
use tauri_plugin_updater::UpdaterExt;
let Ok(updater) = handle.updater() else { return };
let nueva = match updater.check().await {
Ok(Some(u)) => u.version,
Ok(None) => return,
Err(e) => {
salud::anotar("AVISO", "actualizacion", &format!("no se pudo comprobar: {e}"));
return;
}
};
let ya = PENDIENTE.lock().map(|mut p| p.replace(nueva.clone())).unwrap_or(None);
if ya.as_deref() == Some(nueva.as_str()) {
return;
}
salud::anotar("INFO", "actualizacion", &format!("hay versión nueva ({nueva}): espera a que se pulse «Actualizar»"));
broadcast(&handle);
let _ = handle
.notification()
.builder()
.title("Labstream OS")
.body(format!("Hay una versión nueva ({nueva}). Pulsa «Actualizar» en la barra de pestañas: la app se reinicia y vuelve a abrir tus pestañas."))
.show();
}
// Busca e instala una actualización en segundo plano. Si instala, avisa y reinicia. // Busca e instala una actualización en segundo plano. Si instala, avisa y reinicia.
#[cfg(desktop)] #[cfg(desktop)]
async fn check_update(handle: tauri::AppHandle) { async fn check_update(handle: tauri::AppHandle) {
@@ -1725,6 +1768,15 @@ pub fn run() {
let handle = app.handle().clone(); let handle = app.handle().clone();
tauri::async_runtime::spawn(check_update(handle)); tauri::async_runtime::spawn(check_update(handle));
} }
// Y después, cada hora, sin instalarla: la barra ofrece «Actualizar» (ver PENDIENTE).
#[cfg(desktop)]
{
let handle = app.handle().clone();
std::thread::spawn(move || loop {
std::thread::sleep(BUSCAR_CADA);
tauri::async_runtime::block_on(buscar_sin_instalar(handle.clone()));
});
}
{ {
let shell = handle.state::<ShellState>(); let shell = handle.state::<ShellState>();

Ver fichero

@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Labstream OS", "productName": "Labstream OS",
"version": "1.23.0", "version": "1.24.0",
"identifier": "co.labstream.os", "identifier": "co.labstream.os",
"build": { "build": {
"frontendDist": "../dist" "frontendDist": "../dist"