Fix misleading 'Update installed' callout flash

The install flow briefly flashed an "Update installed / Restart to use
the new version" callout between clicking Install & restart and the
actual app quit. The button implies action; the restart is already in
flight.

Run quitAndInstall inline (no 1.5s setTimeout) so the IPC sequences
download → install → daemon stop → app quit before returning. Drop the
"installed" rendering branch from the callout so the success path goes
straight from "Installing..." to the window unmounting.
This commit is contained in:
Mohamed Boudra
2026-05-07 18:20:22 +07:00
parent 4fa1db8d06
commit 2d9c7747fb
2 changed files with 10 additions and 33 deletions

View File

@@ -13,25 +13,18 @@ import { openExternalUrl } from "@/utils/open-external-url";
const CHECK_INTERVAL_MS = 30 * 60 * 1000; const CHECK_INTERVAL_MS = 30 * 60 * 1000;
const CHANGELOG_URL = "https://paseo.sh/changelog"; const CHANGELOG_URL = "https://paseo.sh/changelog";
function resolveUpdateCalloutTitle(args: { function resolveUpdateCalloutTitle(args: { isInstalling: boolean; isError: boolean }): string {
isInstalled: boolean;
isInstalling: boolean;
isError: boolean;
}): string {
if (args.isInstalled) return "Update installed";
if (args.isInstalling) return "Installing update"; if (args.isInstalling) return "Installing update";
if (args.isError) return "Update failed"; if (args.isError) return "Update failed";
return "Update available"; return "Update available";
} }
function resolveUpdateCalloutDescription(args: { function resolveUpdateCalloutDescription(args: {
isInstalled: boolean;
isInstalling: boolean; isInstalling: boolean;
isError: boolean; isError: boolean;
errorMessage: string | null; errorMessage: string | null;
latestVersion: string | undefined; latestVersion: string | undefined;
}): ReactNode { }): ReactNode {
if (args.isInstalled) return "Restart to use the new version.";
if (args.isInstalling) return "Installing and restarting..."; if (args.isInstalling) return "Installing and restarting...";
if (args.isError) return args.errorMessage ?? "Something went wrong."; if (args.isError) return args.errorMessage ?? "Something went wrong.";
if (args.latestVersion) { if (args.latestVersion) {
@@ -43,7 +36,6 @@ function resolveUpdateCalloutDescription(args: {
} }
function buildUpdateCalloutActions(args: { function buildUpdateCalloutActions(args: {
isInstalled: boolean;
isInstalling: boolean; isInstalling: boolean;
isError: boolean; isError: boolean;
openChangelog: () => void; openChangelog: () => void;
@@ -53,7 +45,7 @@ function buildUpdateCalloutActions(args: {
const actions: SidebarCalloutAction[] = [{ label: "What's new", onPress: args.openChangelog }]; const actions: SidebarCalloutAction[] = [{ label: "What's new", onPress: args.openChangelog }];
if (args.isError) { if (args.isError) {
actions.push({ label: "Retry", onPress: args.retry, variant: "primary" }); actions.push({ label: "Retry", onPress: args.retry, variant: "primary" });
} else if (!args.isInstalled) { } else {
actions.push({ actions.push({
label: args.isInstalling ? "Installing..." : "Install & restart", label: args.isInstalling ? "Installing..." : "Install & restart",
onPress: args.install, onPress: args.install,
@@ -107,29 +99,21 @@ export function UpdateCalloutSource() {
if (!isDesktopApp) { if (!isDesktopApp) {
return; return;
} }
if ( if (status !== "available" && status !== "installing" && status !== "error") {
status !== "available" &&
status !== "installed" &&
status !== "installing" &&
status !== "error"
) {
return; return;
} }
const isInstalled = status === "installed";
const isError = status === "error"; const isError = status === "error";
const isAvailable = !isInstalled && !isInstalling && !isError; const isAvailable = !isInstalling && !isError;
const title = resolveUpdateCalloutTitle({ isInstalled, isInstalling, isError }); const title = resolveUpdateCalloutTitle({ isInstalling, isError });
const description = resolveUpdateCalloutDescription({ const description = resolveUpdateCalloutDescription({
isInstalled,
isInstalling, isInstalling,
isError, isError,
errorMessage, errorMessage,
latestVersion: availableUpdate?.latestVersion ?? undefined, latestVersion: availableUpdate?.latestVersion ?? undefined,
}); });
const actions = buildUpdateCalloutActions({ const actions = buildUpdateCalloutActions({
isInstalled,
isInstalling, isInstalling,
isError, isError,
openChangelog, openChangelog,

View File

@@ -196,16 +196,9 @@ function buildCheckResult(input: {
}; };
} }
function scheduleQuitAndInstall(onBeforeQuit?: () => Promise<void>): void { async function performQuitAndInstall(onBeforeQuit?: () => Promise<void>): Promise<void> {
// Use a short delay to allow the renderer to receive the response. if (onBeforeQuit) await onBeforeQuit();
setTimeout(async () => { autoUpdater.quitAndInstall(/* isSilent */ false, /* isForceRunAfter */ true);
try {
if (onBeforeQuit) await onBeforeQuit();
autoUpdater.quitAndInstall(/* isSilent */ false, /* isForceRunAfter */ true);
} catch (error) {
console.error("[auto-updater] quitAndInstall failed:", error);
}
}, 1500);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -314,7 +307,7 @@ export async function downloadAndInstallUpdate(
const readyVersion = cachedUpdateInfo.version; const readyVersion = cachedUpdateInfo.version;
if (isReadyToInstallVersion(readyVersion)) { if (isReadyToInstallVersion(readyVersion)) {
scheduleQuitAndInstall(onBeforeQuit); await performQuitAndInstall(onBeforeQuit);
return { return {
installed: true, installed: true,
version: readyVersion, version: readyVersion,
@@ -336,7 +329,7 @@ export async function downloadAndInstallUpdate(
await autoUpdater.downloadUpdate(); await autoUpdater.downloadUpdate();
downloadedUpdateVersion = readyVersion; downloadedUpdateVersion = readyVersion;
downloading = false; downloading = false;
scheduleQuitAndInstall(onBeforeQuit); await performQuitAndInstall(onBeforeQuit);
return { return {
installed: true, installed: true,