fix(app): preserve agent picker for existing users (#39300)
This commit is contained in:
parent
a45c2b917e
commit
f256a4c538
3 changed files with 45 additions and 3 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import {
|
import {
|
||||||
hasExistingWebState,
|
hasExistingWebState,
|
||||||
|
initialAgentVisibility,
|
||||||
isAppUpgrade,
|
isAppUpgrade,
|
||||||
layoutTransitionState,
|
layoutTransitionState,
|
||||||
maximumSunsetTimeout,
|
maximumSunsetTimeout,
|
||||||
|
|
@ -11,6 +12,22 @@ import {
|
||||||
shouldEnableNewLayout,
|
shouldEnableNewLayout,
|
||||||
} from "./settings"
|
} from "./settings"
|
||||||
|
|
||||||
|
describe("agent visibility", () => {
|
||||||
|
test("shows the picker for existing profiles and hides it for first-time installs", () => {
|
||||||
|
expect(initialAgentVisibility(undefined, true)).toBe(true)
|
||||||
|
expect(initialAgentVisibility(undefined, false)).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("shows the picker when updating from a recent release", () => {
|
||||||
|
expect(initialAgentVisibility(undefined, false, "1.18.8")).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("preserves the preference after initialization", () => {
|
||||||
|
expect(initialAgentVisibility(true, true, "1.18.8")).toBeUndefined()
|
||||||
|
expect(initialAgentVisibility(true, false)).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("layout transition", () => {
|
describe("layout transition", () => {
|
||||||
test("blank profiles default to the new layout", () => {
|
test("blank profiles default to the new layout", () => {
|
||||||
expect(newLayoutDesignsDefault).toBe(true)
|
expect(newLayoutDesignsDefault).toBe(true)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { createStore, reconcile } from "solid-js/store"
|
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 { createSimpleContext } from "@opencode-ai/ui/context"
|
||||||
import { persisted } from "@/utils/persist"
|
import { persisted } from "@/utils/persist"
|
||||||
import { usePlatform } from "@/context/platform"
|
import { usePlatform } from "@/context/platform"
|
||||||
|
|
@ -36,6 +36,7 @@ export interface Settings {
|
||||||
mobileTitlebarPosition: "top" | "bottom"
|
mobileTitlebarPosition: "top" | "bottom"
|
||||||
newLayoutDesigns?: boolean
|
newLayoutDesigns?: boolean
|
||||||
layoutTransitionEligible?: boolean
|
layoutTransitionEligible?: boolean
|
||||||
|
agentVisibilityInitialized?: boolean
|
||||||
newInterfaceNoticeDismissed?: boolean
|
newInterfaceNoticeDismissed?: boolean
|
||||||
shouldDisplayTabsToast?: boolean
|
shouldDisplayTabsToast?: boolean
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +94,15 @@ export function hasExistingWebState(settings: Promise<string> | string | null, p
|
||||||
return settings !== null || previousVersion !== undefined
|
return settings !== null || previousVersion !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initialAgentVisibility(
|
||||||
|
initialized: boolean | undefined,
|
||||||
|
existing: boolean,
|
||||||
|
previousVersion?: string,
|
||||||
|
) {
|
||||||
|
if (initialized === true) return
|
||||||
|
return existing || previousVersion !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
export function shouldEnableNewLayout(previous: string | undefined, current: string | undefined) {
|
export function shouldEnableNewLayout(previous: string | undefined, current: string | undefined) {
|
||||||
if (!current) return false
|
if (!current) return false
|
||||||
const currentComparison = compareVersions(current, newLayoutDesignsUpgradeCutoff)
|
const currentComparison = compareVersions(current, newLayoutDesignsUpgradeCutoff)
|
||||||
|
|
@ -271,6 +281,18 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
const visible = (preference: () => boolean) => createMemo(() => !newLayoutDesigns() || preference())
|
const visible = (preference: () => boolean) => createMemo(() => !newLayoutDesigns() || preference())
|
||||||
|
const initializeAgentVisibility = (existing: boolean) => {
|
||||||
|
const initial = initialAgentVisibility(
|
||||||
|
store.general?.agentVisibilityInitialized,
|
||||||
|
existing,
|
||||||
|
launchState.previous,
|
||||||
|
)
|
||||||
|
if (initial === undefined) return
|
||||||
|
batch(() => {
|
||||||
|
setStore("general", "showCustomAgents", initial)
|
||||||
|
setStore("general", "agentVisibilityInitialized", true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (sunset && !oldInterfaceRetired()) {
|
if (sunset && !oldInterfaceRetired()) {
|
||||||
const timeout = { current: undefined as ReturnType<typeof setTimeout> | undefined }
|
const timeout = { current: undefined as ReturnType<typeof setTimeout> | undefined }
|
||||||
|
|
@ -299,8 +321,9 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!ready() || !launchState.classified || platform.platform !== "web") return
|
if (!ready() || !launchState.classified || platform.platform !== "web") return
|
||||||
if (layoutTransitionClassified()) return
|
const existing = hasExistingWebState(settingsInit, launchState.previous)
|
||||||
setStore("general", "layoutTransitionEligible", hasExistingWebState(settingsInit, launchState.previous))
|
if (!layoutTransitionClassified()) setStore("general", "layoutTransitionEligible", existing)
|
||||||
|
initializeAgentVisibility(existing)
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
|
|
@ -426,6 +449,7 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
|
||||||
if (typeof current === "boolean") return
|
if (typeof current === "boolean") return
|
||||||
setStore("general", "layoutTransitionEligible", eligible)
|
setStore("general", "layoutTransitionEligible", eligible)
|
||||||
},
|
},
|
||||||
|
initializeAgentVisibility,
|
||||||
layoutTransitionAvailable: createMemo(() => ready() && layoutTransition().available),
|
layoutTransitionAvailable: createMemo(() => ready() && layoutTransition().available),
|
||||||
newInterfaceNoticeVisible: createMemo(() => ready() && layoutTransition().notice),
|
newInterfaceNoticeVisible: createMemo(() => ready() && layoutTransition().notice),
|
||||||
dismissNewInterfaceNotice() {
|
dismissNewInterfaceNotice() {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ export function DesktopFirstLaunchOnboarding(props: { initialUrl: string; onLoad
|
||||||
)
|
)
|
||||||
const existingInstall = await window.api.isOldLayoutEligible()
|
const existingInstall = await window.api.isOldLayoutEligible()
|
||||||
settings.general.setOldLayoutEligible(existingInstall)
|
settings.general.setOldLayoutEligible(existingInstall)
|
||||||
|
settings.general.initializeAgentVisibility(existingInstall)
|
||||||
if (!server.isLocal()) return
|
if (!server.isLocal()) return
|
||||||
|
|
||||||
const pending = await window.api.isFirstLaunchOnboardingPending()
|
const pending = await window.api.isFirstLaunchOnboardingPending()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue