From d6348b3307fce1474f3c13900e1d70224569937d Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 08:50:10 +0100 Subject: [PATCH 1/7] feat(updates): add auto-download setting --- apps/code/src/main/services/settingsStore.ts | 14 ++++++ .../code/src/main/services/updates/schemas.ts | 8 +++ .../src/main/services/updates/service.test.ts | 31 ++++++++++++ .../code/src/main/services/updates/service.ts | 36 ++++++++++--- apps/code/src/main/trpc/routers/updates.ts | 15 ++++++ .../components/sections/UpdatesSettings.tsx | 50 ++++++++++++++++++- 6 files changed, 147 insertions(+), 7 deletions(-) diff --git a/apps/code/src/main/services/settingsStore.ts b/apps/code/src/main/services/settingsStore.ts index 2acf4a02f..774b75b78 100644 --- a/apps/code/src/main/services/settingsStore.ts +++ b/apps/code/src/main/services/settingsStore.ts @@ -11,6 +11,7 @@ interface SettingsSchema { autoSuspendEnabled: boolean; maxActiveWorktrees: number; autoSuspendAfterDays: number; + autoDownloadUpdates: boolean; } function getDefaultWorktreeLocation(): string { @@ -84,6 +85,10 @@ const schema = { minimum: 1, maximum: 365, }, + autoDownloadUpdates: { + type: "boolean" as const, + default: true, + }, }; export const settingsStore = new Store({ @@ -96,6 +101,7 @@ export const settingsStore = new Store({ autoSuspendEnabled: true, maxActiveWorktrees: 5, autoSuspendAfterDays: 7, + autoDownloadUpdates: true, }, }); @@ -166,3 +172,11 @@ export function getAutoSuspendAfterDays(): number { export function setAutoSuspendAfterDays(value: number): void { settingsStore.set("autoSuspendAfterDays", value); } + +export function getAutoDownloadUpdatesEnabled(): boolean { + return settingsStore.get("autoDownloadUpdates", true); +} + +export function setAutoDownloadUpdatesEnabled(value: boolean): void { + settingsStore.set("autoDownloadUpdates", value); +} diff --git a/apps/code/src/main/services/updates/schemas.ts b/apps/code/src/main/services/updates/schemas.ts index dbdef957a..606d5ce97 100644 --- a/apps/code/src/main/services/updates/schemas.ts +++ b/apps/code/src/main/services/updates/schemas.ts @@ -17,6 +17,14 @@ export const installUpdateOutput = z.object({ installed: z.boolean(), }); +export const autoDownloadUpdatesOutput = z.object({ + enabled: z.boolean(), +}); + +export const setAutoDownloadUpdatesInput = z.object({ + enabled: z.boolean(), +}); + export type IsEnabledOutput = z.infer; export type CheckForUpdatesOutput = z.infer; diff --git a/apps/code/src/main/services/updates/service.test.ts b/apps/code/src/main/services/updates/service.test.ts index a91bae898..dd711350d 100644 --- a/apps/code/src/main/services/updates/service.test.ts +++ b/apps/code/src/main/services/updates/service.test.ts @@ -98,6 +98,14 @@ vi.mock("../../utils/env.js", () => ({ isDevBuild: () => !mockAppMeta.isProduction, })); +const mockAutoDownloadUpdatesEnabled = vi.hoisted(() => vi.fn(() => true)); +const mockSetAutoDownloadUpdatesEnabled = vi.hoisted(() => vi.fn()); + +vi.mock("../settingsStore.js", () => ({ + getAutoDownloadUpdatesEnabled: mockAutoDownloadUpdatesEnabled, + setAutoDownloadUpdatesEnabled: mockSetAutoDownloadUpdatesEnabled, +})); + // Import the service after mocks are set up import { UpdatesService } from "./service"; @@ -135,6 +143,7 @@ describe("UpdatesService", () => { mockAppMeta.version = "1.0.0"; mockUpdater.isSupported.mockReturnValue(true); mockAppLifecycle.whenReady.mockResolvedValue(undefined); + mockAutoDownloadUpdatesEnabled.mockReturnValue(true); // Set default platform to darwin (macOS) Object.defineProperty(process, "platform", { @@ -257,6 +266,16 @@ describe("UpdatesService", () => { expect(mockAppLifecycle.whenReady).not.toHaveBeenCalled(); }); + it("skips startup and periodic checks when auto-download is disabled", async () => { + mockAutoDownloadUpdatesEnabled.mockReturnValue(false); + + await initializeService(service); + + expect(mockUpdater.check).not.toHaveBeenCalled(); + vi.advanceTimersByTime(60 * 60 * 1000); + expect(mockUpdater.check).not.toHaveBeenCalled(); + }); + it("prevents multiple initializations", async () => { await initializeService(service); @@ -404,6 +423,18 @@ describe("UpdatesService", () => { }); }); + describe("settings", () => { + it("reads auto-download toggle from settings store", () => { + mockAutoDownloadUpdatesEnabled.mockReturnValue(false); + expect(service.autoDownloadUpdatesEnabled).toBe(false); + }); + + it("persists auto-download toggle changes", () => { + service.setAutoDownloadUpdatesEnabled(false); + expect(mockSetAutoDownloadUpdatesEnabled).toHaveBeenCalledWith(false); + }); + }); + describe("installUpdate", () => { it("returns false when no update is ready", async () => { const result = await service.installUpdate(); diff --git a/apps/code/src/main/services/updates/service.ts b/apps/code/src/main/services/updates/service.ts index fdbec5d1d..a5f85c888 100644 --- a/apps/code/src/main/services/updates/service.ts +++ b/apps/code/src/main/services/updates/service.ts @@ -8,6 +8,10 @@ import { isDevBuild } from "../../utils/env"; import { logger } from "../../utils/logger"; import { TypedEventEmitter } from "../../utils/typed-event-emitter"; import type { AppLifecycleService } from "../app-lifecycle/service"; +import { + getAutoDownloadUpdatesEnabled, + setAutoDownloadUpdatesEnabled, +} from "../settingsStore"; import { type CheckForUpdatesOutput, type InstallUpdateOutput, @@ -91,6 +95,20 @@ export class UpdatesService extends TypedEventEmitter { this.appLifecycle.whenReady().then(() => this.setupAutoUpdater()); } + get autoDownloadUpdatesEnabled(): boolean { + return getAutoDownloadUpdatesEnabled(); + } + + setAutoDownloadUpdatesEnabled(enabled: boolean): void { + const previous = this.autoDownloadUpdatesEnabled; + setAutoDownloadUpdatesEnabled(enabled); + + log.info("Auto-download updates setting changed", { + previous, + current: enabled, + }); + } + triggerMenuCheck(): void { this.emit(UpdatesEvent.CheckFromMenu, true); } @@ -191,13 +209,19 @@ export class UpdatesService extends TypedEventEmitter { ), ); - // Perform initial check (periodic source — not user-initiated) - this.checkForUpdates("periodic"); + // Perform initial check and periodic checks only when auto-download is enabled + if (this.autoDownloadUpdatesEnabled) { + this.checkForUpdates("periodic"); + + this.checkIntervalId = setInterval( + () => this.checkForUpdates("periodic"), + UpdatesService.CHECK_INTERVAL_MS, + ); + return; + } - // Set up periodic checks - this.checkIntervalId = setInterval( - () => this.checkForUpdates("periodic"), - UpdatesService.CHECK_INTERVAL_MS, + log.info( + "Auto-download updates disabled; skipping startup and periodic checks", ); } diff --git a/apps/code/src/main/trpc/routers/updates.ts b/apps/code/src/main/trpc/routers/updates.ts index 7cabefb5e..3d3b20c6e 100644 --- a/apps/code/src/main/trpc/routers/updates.ts +++ b/apps/code/src/main/trpc/routers/updates.ts @@ -1,9 +1,11 @@ import { container } from "../../di/container"; import { MAIN_TOKENS } from "../../di/tokens"; import { + autoDownloadUpdatesOutput, checkForUpdatesOutput, installUpdateOutput, isEnabledOutput, + setAutoDownloadUpdatesInput, UpdatesEvent, type UpdatesEvents, } from "../../services/updates/schemas"; @@ -39,6 +41,19 @@ export const updatesRouter = router({ return service.installUpdate(); }), + getAutoDownload: publicProcedure + .output(autoDownloadUpdatesOutput) + .query(() => ({ enabled: getService().autoDownloadUpdatesEnabled })), + + setAutoDownload: publicProcedure + .input(setAutoDownloadUpdatesInput) + .output(autoDownloadUpdatesOutput) + .mutation(({ input }) => { + const service = getService(); + service.setAutoDownloadUpdatesEnabled(input.enabled); + return { enabled: service.autoDownloadUpdatesEnabled }; + }), + onReady: subscribe(UpdatesEvent.Ready), onStatus: subscribe(UpdatesEvent.Status), onCheckFromMenu: subscribe(UpdatesEvent.CheckFromMenu), diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index c83f0ce19..2b65a8250 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -1,9 +1,11 @@ import { SettingRow } from "@features/settings/components/SettingRow"; import { CheckCircle, XCircle } from "@phosphor-icons/react"; -import { Badge, Button, Flex, Spinner, Text } from "@radix-ui/themes"; +import { Badge, Button, Flex, Spinner, Switch, Text } from "@radix-ui/themes"; import { useTRPC } from "@renderer/trpc"; +import { ANALYTICS_EVENTS } from "@shared/types/analytics"; import { useMutation, useQuery } from "@tanstack/react-query"; import { useSubscription } from "@trpc/tanstack-react-query"; +import { track } from "@utils/analytics"; import { logger } from "@utils/logger"; import { useCallback, useEffect, useRef, useState } from "react"; @@ -16,6 +18,10 @@ export function UpdatesSettings() { ); const [checkingForUpdates, setCheckingForUpdates] = useState(false); const [updatesDisabled, setUpdatesDisabled] = useState(false); + const { data: autoDownload } = useQuery( + trpcReact.updates.getAutoDownload.queryOptions(), + ); + const [autoDownloadEnabled, setAutoDownloadEnabled] = useState(true); const [updateStatus, setUpdateStatus] = useState<{ message?: string; type?: "info" | "success" | "error"; @@ -25,6 +31,9 @@ export function UpdatesSettings() { const checkUpdatesMutation = useMutation( trpcReact.updates.check.mutationOptions(), ); + const setAutoDownloadMutation = useMutation( + trpcReact.updates.setAutoDownload.mutationOptions(), + ); const handleCheckForUpdates = useCallback(async () => { setCheckingForUpdates(true); @@ -68,6 +77,12 @@ export function UpdatesSettings() { } }, [handleCheckForUpdates]); + useEffect(() => { + if (typeof autoDownload?.enabled === "boolean") { + setAutoDownloadEnabled(autoDownload.enabled); + } + }, [autoDownload?.enabled]); + useSubscription( trpcReact.updates.onStatus.subscriptionOptions(undefined, { onData: (status) => { @@ -102,6 +117,39 @@ export function UpdatesSettings() { + + { + const previous = autoDownloadEnabled; + if (previous === checked) return; + + setAutoDownloadEnabled(checked); + track(ANALYTICS_EVENTS.SETTING_CHANGED, { + setting_name: "auto_download_updates", + old_value: previous, + new_value: checked, + }); + + setAutoDownloadMutation.mutate( + { enabled: checked }, + { + onError: () => { + setAutoDownloadEnabled(previous); + }, + onSuccess: (result) => { + setAutoDownloadEnabled(result.enabled); + }, + }, + ); + }} + disabled={setAutoDownloadMutation.isPending} + /> + + Date: Fri, 8 May 2026 09:26:05 +0100 Subject: [PATCH 2/7] fix(updates): apply auto-download toggle immediately --- .../src/main/services/updates/service.test.ts | 25 +++++++++++ .../code/src/main/services/updates/service.ts | 42 ++++++++++++++----- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/apps/code/src/main/services/updates/service.test.ts b/apps/code/src/main/services/updates/service.test.ts index dd711350d..6fb672fe3 100644 --- a/apps/code/src/main/services/updates/service.test.ts +++ b/apps/code/src/main/services/updates/service.test.ts @@ -433,6 +433,31 @@ describe("UpdatesService", () => { service.setAutoDownloadUpdatesEnabled(false); expect(mockSetAutoDownloadUpdatesEnabled).toHaveBeenCalledWith(false); }); + + it("stops periodic checks when auto-download is disabled at runtime", async () => { + await initializeService(service); + updaterHandlers.noUpdate?.(); + mockUpdater.check.mockClear(); + + service.setAutoDownloadUpdatesEnabled(false); + await vi.advanceTimersByTimeAsync(60 * 60 * 1000); + + expect(mockUpdater.check).not.toHaveBeenCalled(); + }); + + it("starts periodic checks when auto-download is enabled at runtime", async () => { + mockAutoDownloadUpdatesEnabled.mockReturnValue(false); + await initializeService(service); + mockUpdater.check.mockClear(); + + service.setAutoDownloadUpdatesEnabled(true); + expect(mockUpdater.check).toHaveBeenCalledTimes(1); + + updaterHandlers.noUpdate?.(); + await vi.advanceTimersByTimeAsync(60 * 60 * 1000); + + expect(mockUpdater.check).toHaveBeenCalledTimes(2); + }); }); describe("installUpdate", () => { diff --git a/apps/code/src/main/services/updates/service.ts b/apps/code/src/main/services/updates/service.ts index a5f85c888..497c7c3d7 100644 --- a/apps/code/src/main/services/updates/service.ts +++ b/apps/code/src/main/services/updates/service.ts @@ -103,6 +103,14 @@ export class UpdatesService extends TypedEventEmitter { const previous = this.autoDownloadUpdatesEnabled; setAutoDownloadUpdatesEnabled(enabled); + if (this.initialized) { + if (enabled) { + this.startAutoDownloadChecks(); + } else { + this.stopAutoDownloadChecks(); + } + } + log.info("Auto-download updates setting changed", { previous, current: enabled, @@ -209,14 +217,8 @@ export class UpdatesService extends TypedEventEmitter { ), ); - // Perform initial check and periodic checks only when auto-download is enabled if (this.autoDownloadUpdatesEnabled) { - this.checkForUpdates("periodic"); - - this.checkIntervalId = setInterval( - () => this.checkForUpdates("periodic"), - UpdatesService.CHECK_INTERVAL_MS, - ); + this.startAutoDownloadChecks(); return; } @@ -353,13 +355,31 @@ export class UpdatesService extends TypedEventEmitter { } } + private startAutoDownloadChecks(): void { + if (this.checkIntervalId) { + return; + } + + this.checkForUpdates("periodic"); + this.checkIntervalId = setInterval( + () => this.checkForUpdates("periodic"), + UpdatesService.CHECK_INTERVAL_MS, + ); + } + + private stopAutoDownloadChecks(): void { + if (!this.checkIntervalId) { + return; + } + + clearInterval(this.checkIntervalId); + this.checkIntervalId = null; + } + @preDestroy() shutdown(): void { this.clearCheckTimeout(); - if (this.checkIntervalId) { - clearInterval(this.checkIntervalId); - this.checkIntervalId = null; - } + this.stopAutoDownloadChecks(); for (const unsub of this.unsubscribes) unsub(); this.unsubscribes = []; } From 4bfa9f4fe77783906235965401998a7089cc4b2d Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 09:59:49 +0100 Subject: [PATCH 3/7] fix(updates): show check failures in settings --- .../settings/components/sections/UpdatesSettings.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index 2b65a8250..ddb8b92ba 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -102,6 +102,12 @@ export function UpdatesSettings() { type: "success", }); setCheckingForUpdates(false); + } else if (status.checking === false && status.error) { + setUpdateStatus({ + message: status.error, + type: "error", + }); + setCheckingForUpdates(false); } else if (status.checking === false) { setCheckingForUpdates(false); } From 14428856b7b6f9de059646cebd0c0b7879ab7c53 Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 10:28:05 +0100 Subject: [PATCH 4/7] Address auto-update settings review feedback --- .../src/main/services/updates/service.test.ts | 24 ++++--- .../components/sections/UpdatesSettings.tsx | 71 ++++++++++--------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/apps/code/src/main/services/updates/service.test.ts b/apps/code/src/main/services/updates/service.test.ts index 6fb672fe3..ecf05eae0 100644 --- a/apps/code/src/main/services/updates/service.test.ts +++ b/apps/code/src/main/services/updates/service.test.ts @@ -424,15 +424,21 @@ describe("UpdatesService", () => { }); describe("settings", () => { - it("reads auto-download toggle from settings store", () => { - mockAutoDownloadUpdatesEnabled.mockReturnValue(false); - expect(service.autoDownloadUpdatesEnabled).toBe(false); - }); - - it("persists auto-download toggle changes", () => { - service.setAutoDownloadUpdatesEnabled(false); - expect(mockSetAutoDownloadUpdatesEnabled).toHaveBeenCalledWith(false); - }); + it.each([true, false])( + "reads auto-download toggle from settings store (%s)", + (value) => { + mockAutoDownloadUpdatesEnabled.mockReturnValue(value); + expect(service.autoDownloadUpdatesEnabled).toBe(value); + }, + ); + + it.each([true, false])( + "persists auto-download toggle changes (%s)", + (value) => { + service.setAutoDownloadUpdatesEnabled(value); + expect(mockSetAutoDownloadUpdatesEnabled).toHaveBeenCalledWith(value); + }, + ); it("stops periodic checks when auto-download is disabled at runtime", async () => { await initializeService(service); diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index ddb8b92ba..4e0333492 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -21,7 +21,9 @@ export function UpdatesSettings() { const { data: autoDownload } = useQuery( trpcReact.updates.getAutoDownload.queryOptions(), ); - const [autoDownloadEnabled, setAutoDownloadEnabled] = useState(true); + const [autoDownloadEnabled, setAutoDownloadEnabled] = useState< + boolean | undefined + >(undefined); const [updateStatus, setUpdateStatus] = useState<{ message?: string; type?: "info" | "success" | "error"; @@ -71,11 +73,13 @@ export function UpdatesSettings() { }, [checkUpdatesMutation]); useEffect(() => { - if (!hasCheckedRef.current) { - hasCheckedRef.current = true; - handleCheckForUpdates(); + if (hasCheckedRef.current || autoDownload?.enabled !== true) { + return; } - }, [handleCheckForUpdates]); + + hasCheckedRef.current = true; + handleCheckForUpdates(); + }, [autoDownload?.enabled, handleCheckForUpdates]); useEffect(() => { if (typeof autoDownload?.enabled === "boolean") { @@ -125,40 +129,43 @@ export function UpdatesSettings() { - { - const previous = autoDownloadEnabled; - if (previous === checked) return; - - setAutoDownloadEnabled(checked); - track(ANALYTICS_EVENTS.SETTING_CHANGED, { - setting_name: "auto_download_updates", - old_value: previous, - new_value: checked, - }); + {typeof autoDownloadEnabled === "boolean" && ( + { + const previous = autoDownloadEnabled; + if (previous === checked) return; - setAutoDownloadMutation.mutate( - { enabled: checked }, - { - onError: () => { - setAutoDownloadEnabled(previous); - }, - onSuccess: (result) => { - setAutoDownloadEnabled(result.enabled); + setAutoDownloadEnabled(checked); + setAutoDownloadMutation.mutate( + { enabled: checked }, + { + onError: () => { + setAutoDownloadEnabled(previous); + }, + onSuccess: (result) => { + setAutoDownloadEnabled(result.enabled); + if (result.enabled !== previous) { + track(ANALYTICS_EVENTS.SETTING_CHANGED, { + setting_name: "auto_download_updates", + old_value: previous, + new_value: result.enabled, + }); + } + }, }, - }, - ); - }} - disabled={setAutoDownloadMutation.isPending} - /> + ); + }} + disabled={setAutoDownloadMutation.isPending} + /> + )} From 5dbfceb7680101f54b4e5f49e54c71a6273b939c Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 17:21:12 +0100 Subject: [PATCH 5/7] Handle auto-update settings follow-up review --- apps/code/src/main/services/updates/schemas.ts | 6 ++++++ .../settings/components/sections/UpdatesSettings.tsx | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/code/src/main/services/updates/schemas.ts b/apps/code/src/main/services/updates/schemas.ts index 606d5ce97..63c975d18 100644 --- a/apps/code/src/main/services/updates/schemas.ts +++ b/apps/code/src/main/services/updates/schemas.ts @@ -29,6 +29,12 @@ export type IsEnabledOutput = z.infer; export type CheckForUpdatesOutput = z.infer; export type InstallUpdateOutput = z.infer; +export type AutoDownloadUpdatesOutput = z.infer< + typeof autoDownloadUpdatesOutput +>; +export type SetAutoDownloadUpdatesInput = z.infer< + typeof setAutoDownloadUpdatesInput +>; export const UpdatesEvent = { Ready: "ready", diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index 4e0333492..10cee95e5 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -3,7 +3,7 @@ import { CheckCircle, XCircle } from "@phosphor-icons/react"; import { Badge, Button, Flex, Spinner, Switch, Text } from "@radix-ui/themes"; import { useTRPC } from "@renderer/trpc"; import { ANALYTICS_EVENTS } from "@shared/types/analytics"; -import { useMutation, useQuery } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { useSubscription } from "@trpc/tanstack-react-query"; import { track } from "@utils/analytics"; import { logger } from "@utils/logger"; @@ -13,6 +13,7 @@ const log = logger.scope("updates-settings"); export function UpdatesSettings() { const trpcReact = useTRPC(); + const queryClient = useQueryClient(); const { data: appVersion } = useQuery( trpcReact.os.getAppVersion.queryOptions(), ); @@ -147,6 +148,9 @@ export function UpdatesSettings() { }, onSuccess: (result) => { setAutoDownloadEnabled(result.enabled); + void queryClient.invalidateQueries( + trpcReact.updates.getAutoDownload.queryFilter(), + ); if (result.enabled !== previous) { track(ANALYTICS_EVENTS.SETTING_CHANGED, { setting_name: "auto_download_updates", From c677bbc09fa01033dbfc727251562e8a2e7cbb2d Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 20:47:06 +0100 Subject: [PATCH 6/7] Fix auto-update startup check guard --- .../settings/components/sections/UpdatesSettings.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index 10cee95e5..d5e681221 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -74,12 +74,14 @@ export function UpdatesSettings() { }, [checkUpdatesMutation]); useEffect(() => { - if (hasCheckedRef.current || autoDownload?.enabled !== true) { + if (typeof autoDownload?.enabled !== "boolean" || hasCheckedRef.current) { return; } hasCheckedRef.current = true; - handleCheckForUpdates(); + if (autoDownload.enabled) { + handleCheckForUpdates(); + } }, [autoDownload?.enabled, handleCheckForUpdates]); useEffect(() => { From 549bfac1cd06bfb8d7473d677f5b5d5f54934f2b Mon Sep 17 00:00:00 2001 From: Kieran Bond Date: Fri, 8 May 2026 21:18:51 +0100 Subject: [PATCH 7/7] Simplify auto-update analytics tracking --- .../settings/components/sections/UpdatesSettings.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx index d5e681221..60508a4c4 100644 --- a/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx +++ b/apps/code/src/renderer/features/settings/components/sections/UpdatesSettings.tsx @@ -153,13 +153,11 @@ export function UpdatesSettings() { void queryClient.invalidateQueries( trpcReact.updates.getAutoDownload.queryFilter(), ); - if (result.enabled !== previous) { - track(ANALYTICS_EVENTS.SETTING_CHANGED, { - setting_name: "auto_download_updates", - old_value: previous, - new_value: result.enabled, - }); - } + track(ANALYTICS_EVENTS.SETTING_CHANGED, { + setting_name: "auto_download_updates", + old_value: previous, + new_value: result.enabled, + }); }, }, );