Support Beta release channel (#591)

This commit is contained in:
Will Chen
2025-07-07 17:15:02 -07:00
committed by GitHub
parent ab6a9d3b34
commit a93536386b
21 changed files with 181 additions and 2 deletions

View File

@@ -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();
}

View File

@@ -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();
});

View File

@@ -14,5 +14,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": false,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -14,5 +14,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -16,5 +16,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -13,5 +13,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -14,5 +14,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -13,5 +13,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -14,5 +14,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -13,5 +13,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -14,5 +14,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -23,5 +23,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -23,5 +23,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -23,5 +23,6 @@
"selectedChatMode": "build",
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isTestMode": true
}

View File

@@ -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 (
<div className="space-y-1">
<div className="flex items-center space-x-2">
<label
htmlFor="release-channel"
className="text-sm font-medium text-gray-700 dark:text-gray-300"
>
Release Channel
</label>
<Select
value={settings.releaseChannel}
onValueChange={handleReleaseChannelChange}
>
<SelectTrigger className="w-32" id="release-channel">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="stable">Stable</SelectItem>
<SelectItem value="beta">Beta</SelectItem>
</SelectContent>
</Select>
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
<p>Stable is recommended for most users. </p>
<p>Beta receives more frequent updates but may have more bugs.</p>
</div>
</div>
);
}

View File

@@ -125,6 +125,9 @@ export type ContextPathResults = {
smartContextAutoIncludes: ContextPathResult[];
};
export const ReleaseChannelSchema = z.enum(["stable", "beta"]);
export type ReleaseChannel = z.infer<typeof ReleaseChannelSchema>;
/**
* 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.

View File

@@ -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

View File

@@ -22,6 +22,7 @@ const DEFAULT_SETTINGS: UserSettings = {
selectedChatMode: "build",
enableAutoFixProblems: false,
enableAutoUpdate: true,
releaseChannel: "stable",
};
const SETTINGS_FILE = "user-settings.json";

View File

@@ -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 }) {
</div>
</div>
<div className="mt-4">
<ReleaseChannelSelector />
</div>
<div className="flex items-center text-sm text-gray-500 dark:text-gray-400 mt-4">
<span className="mr-2 font-medium">App Version:</span>
<span className="bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded text-gray-800 dark:text-gray-200 font-mono">