diff --git a/e2e-tests/helpers/test_helper.ts b/e2e-tests/helpers/test_helper.ts index 4453015..a93650e 100644 --- a/e2e-tests/helpers/test_helper.ts +++ b/e2e-tests/helpers/test_helper.ts @@ -837,6 +837,15 @@ export class PageObject { await this.page.getByRole("switch", { name: "Auto-update" }).click(); } + async changeReleaseChannel(channel: "stable" | "beta") { + // await page.getByRole('combobox').filter({ hasText: 'Stable' }).click(); + // await page.getByRole('option', { name: 'Beta' }).dblclick(); + await this.page.getByRole("combobox", { name: "Release Channel" }).click(); + await this.page + .getByRole("option", { name: channel === "stable" ? "Stable" : "Beta" }) + .click(); + } + async clickTelemetryAccept() { await this.page.getByTestId("telemetry-accept-button").click(); } diff --git a/e2e-tests/release_channel.spec.ts b/e2e-tests/release_channel.spec.ts new file mode 100644 index 0000000..9f743a4 --- /dev/null +++ b/e2e-tests/release_channel.spec.ts @@ -0,0 +1,22 @@ +import { expect } from "@playwright/test"; +import { test } from "./helpers/test_helper"; + +test("release channel - change from stable to beta and back", async ({ + po, +}) => { + await po.goToSettingsTab(); + + // Change to beta channel + await po.changeReleaseChannel("beta"); + await expect( + po.page.getByRole("button", { name: "Restart Dyad" }), + ).toBeVisible(); + await po.snapshotSettings(); + + // Change back to stable channel + await po.changeReleaseChannel("stable"); + await expect( + po.page.getByRole("button", { name: "Download Stable" }), + ).toBeVisible(); + await po.snapshotSettings(); +}); diff --git a/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-1.txt b/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-1.txt index da4fa25..7d57db0 100644 --- a/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-1.txt +++ b/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-1.txt @@ -14,5 +14,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": false, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-2.txt b/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-2.txt index 2e1bf3b..de5b5fe 100644 --- a/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-2.txt +++ b/e2e-tests/snapshots/auto_update.spec.ts_auto-update---disable-and-enable-2.txt @@ -14,5 +14,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt b/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt index fd7eebb..d9fe5fa 100644 --- a/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt +++ b/e2e-tests/snapshots/context_window.spec.ts_context-window-4.txt @@ -16,5 +16,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-1.txt b/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-1.txt new file mode 100644 index 0000000..9679f90 --- /dev/null +++ b/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-1.txt @@ -0,0 +1,19 @@ +{ + "selectedModel": { + "name": "auto", + "provider": "auto" + }, + "providerSettings": {}, + "telemetryConsent": "unset", + "telemetryUserId": "[UUID]", + "hasRunBefore": true, + "experiments": {}, + "lastShownReleaseNotesVersion": "[scrubbed]", + "enableProLazyEditsMode": true, + "enableProSmartFilesContextMode": true, + "selectedChatMode": "build", + "enableAutoFixProblems": false, + "enableAutoUpdate": true, + "releaseChannel": "beta", + "isTestMode": true +} \ No newline at end of file diff --git a/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-2.txt b/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-2.txt new file mode 100644 index 0000000..de5b5fe --- /dev/null +++ b/e2e-tests/snapshots/release_channel.spec.ts_release-channel---change-from-stable-to-beta-and-back-2.txt @@ -0,0 +1,19 @@ +{ + "selectedModel": { + "name": "auto", + "provider": "auto" + }, + "providerSettings": {}, + "telemetryConsent": "unset", + "telemetryUserId": "[UUID]", + "hasRunBefore": true, + "experiments": {}, + "lastShownReleaseNotesVersion": "[scrubbed]", + "enableProLazyEditsMode": true, + "enableProSmartFilesContextMode": true, + "selectedChatMode": "build", + "enableAutoFixProblems": false, + "enableAutoUpdate": true, + "releaseChannel": "stable", + "isTestMode": true +} \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt index b19297a..728da7e 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-1.txt @@ -13,5 +13,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt index 840f152..26da4cb 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---accept-2.txt @@ -14,5 +14,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt index b19297a..728da7e 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-1.txt @@ -13,5 +13,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt index 2e1bf3b..de5b5fe 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---later-2.txt @@ -14,5 +14,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt index b19297a..728da7e 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-1.txt @@ -13,5 +13,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt index 74242ef..f96c256 100644 --- a/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt +++ b/e2e-tests/snapshots/telemetry.spec.ts_telemetry---reject-2.txt @@ -14,5 +14,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt index 679208c..ea85ddb 100644 --- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt +++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-1.txt @@ -23,5 +23,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt index 639ac63..2cc2d59 100644 --- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt +++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-3.txt @@ -23,5 +23,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt index d245e7a..ac7a9ba 100644 --- a/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt +++ b/e2e-tests/snapshots/thinking_budget.spec.ts_thinking-budget-5.txt @@ -23,5 +23,6 @@ "selectedChatMode": "build", "enableAutoFixProblems": false, "enableAutoUpdate": true, + "releaseChannel": "stable", "isTestMode": true } \ No newline at end of file diff --git a/src/components/ReleaseChannelSelector.tsx b/src/components/ReleaseChannelSelector.tsx new file mode 100644 index 0000000..c264b52 --- /dev/null +++ b/src/components/ReleaseChannelSelector.tsx @@ -0,0 +1,76 @@ +import { useSettings } from "@/hooks/useSettings"; + +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { toast } from "sonner"; +import { IpcClient } from "@/ipc/ipc_client"; +import type { ReleaseChannel } from "@/lib/schemas"; + +export function ReleaseChannelSelector() { + const { settings, updateSettings } = useSettings(); + + if (!settings) { + return null; + } + + const handleReleaseChannelChange = (value: ReleaseChannel) => { + updateSettings({ releaseChannel: value }); + if (value === "stable") { + toast("Using Stable release channel", { + description: + "You'll stay on your current version until a newer stable release is available, or you can manually downgrade now.", + action: { + label: "Download Stable", + onClick: () => { + IpcClient.getInstance().openExternalUrl("https://dyad.sh/download"); + }, + }, + }); + } else { + toast("Using Beta release channel", { + description: + "You will need to restart Dyad for your settings to take effect.", + action: { + label: "Restart Dyad", + onClick: () => { + IpcClient.getInstance().restartDyad(); + }, + }, + }); + } + }; + + return ( +
+
+ + +
+
+

Stable is recommended for most users.

+

Beta receives more frequent updates but may have more bugs.

+
+
+ ); +} diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts index 4965ed7..5e75850 100644 --- a/src/lib/schemas.ts +++ b/src/lib/schemas.ts @@ -125,6 +125,9 @@ export type ContextPathResults = { smartContextAutoIncludes: ContextPathResult[]; }; +export const ReleaseChannelSchema = z.enum(["stable", "beta"]); +export type ReleaseChannel = z.infer; + /** * Zod schema for user settings */ @@ -152,6 +155,7 @@ export const UserSettingsSchema = z.object({ enableAutoFixProblems: z.boolean().optional(), enableNativeGit: z.boolean().optional(), enableAutoUpdate: z.boolean(), + releaseChannel: ReleaseChannelSchema, //////////////////////////////// // E2E TESTING ONLY. diff --git a/src/main.ts b/src/main.ts index af3e4f0..48a86b6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import { registerIpcHandlers } from "./ipc/ipc_host"; import dotenv from "dotenv"; // @ts-ignore import started from "electron-squirrel-startup"; -import { updateElectronApp } from "update-electron-app"; +import { updateElectronApp, UpdateSourceType } from "update-electron-app"; import log from "electron-log"; import { readSettings, writeSettings } from "./main/settings"; import { handleSupabaseOAuthReturn } from "./supabase_admin/supabase_return_handler"; @@ -20,7 +20,19 @@ const logger = log.scope("main"); // Check settings before enabling auto-update const settings = readSettings(); if (settings.enableAutoUpdate) { - updateElectronApp({ logger }); // additional configuration options available + // Technically we could just pass the releaseChannel directly to the host, + // but this is more explicit and falls back to stable if there's an unknown + // release channel. + const postfix = settings.releaseChannel === "beta" ? "beta" : "stable"; + const host = `https://api.dyad.sh/v1/update/${postfix}`; + updateElectronApp({ + logger, + updateSource: { + type: UpdateSourceType.ElectronPublicUpdateService, + repo: "dyad-sh/dyad", + host, + }, + }); // additional configuration options available } // Load environment variables from .env file diff --git a/src/main/settings.ts b/src/main/settings.ts index fc7f376..1f6b49c 100644 --- a/src/main/settings.ts +++ b/src/main/settings.ts @@ -22,6 +22,7 @@ const DEFAULT_SETTINGS: UserSettings = { selectedChatMode: "build", enableAutoFixProblems: false, enableAutoUpdate: true, + releaseChannel: "stable", }; const SETTINGS_FILE = "user-settings.json"; diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx index 6c279e3..752b732 100644 --- a/src/pages/settings.tsx +++ b/src/pages/settings.tsx @@ -19,6 +19,7 @@ import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import { AutoFixProblemsSwitch } from "@/components/AutoFixProblemsSwitch"; import { AutoUpdateSwitch } from "@/components/AutoUpdateSwitch"; +import { ReleaseChannelSelector } from "@/components/ReleaseChannelSelector"; export default function SettingsPage() { const [isResetDialogOpen, setIsResetDialogOpen] = useState(false); @@ -270,6 +271,10 @@ export function GeneralSettings({ appVersion }: { appVersion: string | null }) { +
+ +
+
App Version: