Compare commits

...
Author SHA1 Message Date
Brendan Allan 8be1e25cd5 fix(app): preserve agent picker for existing users 2026-07-28 16:38:05 +08:00
3 changed files with 33 additions and 3 deletions
+13
View File
@@ -1,6 +1,7 @@
import { describe, expect, test } from "bun:test"
import {
hasExistingWebState,
initialAgentVisibility,
isAppUpgrade,
layoutTransitionState,
maximumSunsetTimeout,
@@ -11,6 +12,18 @@ import {
shouldEnableNewLayout,
} from "./settings"
describe("agent visibility", () => {
test("shows the picker for existing profiles and hides it for new profiles", () => {
expect(initialAgentVisibility(undefined, true)).toBe(true)
expect(initialAgentVisibility(undefined, false)).toBe(false)
})
test("preserves the preference after initialization", () => {
expect(initialAgentVisibility(true, true)).toBeUndefined()
expect(initialAgentVisibility(true, false)).toBeUndefined()
})
})
describe("layout transition", () => {
test("blank profiles default to the new layout", () => {
expect(newLayoutDesignsDefault).toBe(true)
+19 -3
View File
@@ -1,5 +1,5 @@
import { createStore, reconcile } from "solid-js/store"
import { createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { batch, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { persisted } from "@/utils/persist"
import { usePlatform } from "@/context/platform"
@@ -36,6 +36,7 @@ export interface Settings {
mobileTitlebarPosition: "top" | "bottom"
newLayoutDesigns?: boolean
layoutTransitionEligible?: boolean
agentVisibilityInitialized?: boolean
newInterfaceNoticeDismissed?: boolean
shouldDisplayTabsToast?: boolean
}
@@ -93,6 +94,11 @@ export function hasExistingWebState(settings: Promise<string> | string | null, p
return settings !== null || previousVersion !== undefined
}
export function initialAgentVisibility(initialized: boolean | undefined, existing: boolean) {
if (initialized === true) return
return existing
}
export function shouldEnableNewLayout(previous: string | undefined, current: string | undefined) {
if (!current) return false
const currentComparison = compareVersions(current, newLayoutDesignsUpgradeCutoff)
@@ -271,6 +277,14 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
)
})
const visible = (preference: () => boolean) => createMemo(() => !newLayoutDesigns() || preference())
const initializeAgentVisibility = (existing: boolean) => {
const initial = initialAgentVisibility(store.general?.agentVisibilityInitialized, existing)
if (initial === undefined) return
batch(() => {
setStore("general", "showCustomAgents", initial)
setStore("general", "agentVisibilityInitialized", true)
})
}
if (sunset && !oldInterfaceRetired()) {
const timeout = { current: undefined as ReturnType<typeof setTimeout> | undefined }
@@ -299,8 +313,9 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
createEffect(() => {
if (!ready() || !launchState.classified || platform.platform !== "web") return
if (layoutTransitionClassified()) return
setStore("general", "layoutTransitionEligible", hasExistingWebState(settingsInit, launchState.previous))
const existing = hasExistingWebState(settingsInit, launchState.previous)
if (!layoutTransitionClassified()) setStore("general", "layoutTransitionEligible", existing)
initializeAgentVisibility(existing)
})
createEffect(() => {
@@ -426,6 +441,7 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
if (typeof current === "boolean") return
setStore("general", "layoutTransitionEligible", eligible)
},
initializeAgentVisibility,
layoutTransitionAvailable: createMemo(() => ready() && layoutTransition().available),
newInterfaceNoticeVisible: createMemo(() => ready() && layoutTransition().notice),
dismissNewInterfaceNotice() {
@@ -17,6 +17,7 @@ export function DesktopFirstLaunchOnboarding(props: { initialUrl: string; onLoad
)
const existingInstall = await window.api.isOldLayoutEligible()
settings.general.setOldLayoutEligible(existingInstall)
settings.general.initializeAgentVisibility(existingInstall)
if (!server.isLocal()) return
const pending = await window.api.isFirstLaunchOnboardingPending()