From 1a25d1f8ccb58862ef2364b72d27848e41ec96c9 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 18 May 2026 13:29:45 -0500 Subject: [PATCH] Preserve experimental settings with retired flags Co-Authored-By: Paperclip --- .../instance-settings-service.test.ts | 23 +++++++++++++ server/src/services/instance-settings.ts | 8 +++-- ui/src/pages/Inbox.test.tsx | 32 +++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 server/src/__tests__/instance-settings-service.test.ts diff --git a/server/src/__tests__/instance-settings-service.test.ts b/server/src/__tests__/instance-settings-service.test.ts new file mode 100644 index 00000000000..6669414d697 --- /dev/null +++ b/server/src/__tests__/instance-settings-service.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; +import { normalizeExperimentalSettings } from "../services/instance-settings.js"; + +describe("instance settings service", () => { + it("ignores retired experimental flags without resetting current settings", () => { + expect(normalizeExperimentalSettings({ + enableEnvironments: true, + enableIsolatedWorkspaces: true, + enableCloudSync: true, + autoRestartDevServerWhenIdle: true, + enableIssueGraphLivenessAutoRecovery: true, + issueGraphLivenessAutoRecoveryLookbackHours: 48, + enableNewestFirstIssueThread: true, + })).toEqual({ + enableEnvironments: true, + enableIsolatedWorkspaces: true, + enableCloudSync: true, + autoRestartDevServerWhenIdle: true, + enableIssueGraphLivenessAutoRecovery: true, + issueGraphLivenessAutoRecoveryLookbackHours: 48, + }); + }); +}); diff --git a/server/src/services/instance-settings.ts b/server/src/services/instance-settings.ts index 6c50a67f517..8b02f57c39d 100644 --- a/server/src/services/instance-settings.ts +++ b/server/src/services/instance-settings.ts @@ -15,9 +15,11 @@ import { import { eq } from "drizzle-orm"; const DEFAULT_SINGLETON_KEY = "default"; +const instanceGeneralSettingsStorageSchema = instanceGeneralSettingsSchema.strip(); +const instanceExperimentalSettingsStorageSchema = instanceExperimentalSettingsSchema.strip(); function normalizeGeneralSettings(raw: unknown): InstanceGeneralSettings { - const parsed = instanceGeneralSettingsSchema.safeParse(raw ?? {}); + const parsed = instanceGeneralSettingsStorageSchema.safeParse(raw ?? {}); if (parsed.success) { return { censorUsernameInLogs: parsed.data.censorUsernameInLogs ?? false, @@ -35,8 +37,8 @@ function normalizeGeneralSettings(raw: unknown): InstanceGeneralSettings { }; } -function normalizeExperimentalSettings(raw: unknown): InstanceExperimentalSettings { - const parsed = instanceExperimentalSettingsSchema.safeParse(raw ?? {}); +export function normalizeExperimentalSettings(raw: unknown): InstanceExperimentalSettings { + const parsed = instanceExperimentalSettingsStorageSchema.safeParse(raw ?? {}); if (parsed.success) { return { enableEnvironments: parsed.data.enableEnvironments ?? false, diff --git a/ui/src/pages/Inbox.test.tsx b/ui/src/pages/Inbox.test.tsx index 1c4d5b61571..a136419143b 100644 --- a/ui/src/pages/Inbox.test.tsx +++ b/ui/src/pages/Inbox.test.tsx @@ -295,6 +295,38 @@ describe("Inbox toolbar", () => { }); }); + it("hides workspace grouping when isolated workspaces are disabled", async () => { + routerMock.location.pathname = "/inbox/mine"; + apiMocks.experimentalSettings.mockResolvedValue({ enableIsolatedWorkspaces: false }); + + const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false, staleTime: 0, gcTime: 0 } }, + }); + const root = createRoot(container); + + await act(async () => { + root.render( + + + , + ); + }); + + const groupButton = container.querySelector('button[title="Group"]'); + expect(groupButton).not.toBeNull(); + + await act(async () => { + groupButton?.dispatchEvent(new MouseEvent("click", { bubbles: true })); + }); + + const groupOptions = Array.from(document.body.querySelectorAll("button")).map((button) => button.textContent); + expect(groupOptions).not.toContain("Workspace"); + + act(() => { + root.unmount(); + }); + }); + it("syncs hover with j/k selection on inbox rows", async () => { routerMock.location.pathname = "/inbox/mine"; const issueA = createIssue({ id: "issue-a", identifier: "PAP-1001", title: "First inbox row" });