diff --git a/packages/shared/src/types/instance.ts b/packages/shared/src/types/instance.ts index b34581ba74e..7422c8a6987 100644 --- a/packages/shared/src/types/instance.ts +++ b/packages/shared/src/types/instance.ts @@ -57,6 +57,7 @@ export interface InstanceExperimentalSettings { enableCloudSync: boolean; enableExternalObjects: boolean; enableBuiltInAgents: boolean; + enableDecisions: boolean; enableGoalsSidebarLink: boolean; enableServerInfoDebugView: boolean; autoRestartDevServerWhenIdle: boolean; diff --git a/packages/shared/src/validators/instance.test.ts b/packages/shared/src/validators/instance.test.ts index 09b0c344729..312c3f19aed 100644 --- a/packages/shared/src/validators/instance.test.ts +++ b/packages/shared/src/validators/instance.test.ts @@ -46,6 +46,22 @@ describe("instance experimental settings validators", () => { }); }); + it("defaults the decisions sidebar link off", () => { + const settings = instanceExperimentalSettingsSchema.parse({}); + + expect(settings.enableDecisions).toBe(false); + }); + + it("accepts decisions patches", () => { + expect( + patchInstanceExperimentalSettingsSchema.parse({ + enableDecisions: true, + }), + ).toEqual({ + enableDecisions: true, + }); + }); + it("accepts server info debug view patches", () => { expect( patchInstanceExperimentalSettingsSchema.parse({ diff --git a/packages/shared/src/validators/instance.ts b/packages/shared/src/validators/instance.ts index 612e5d1a19f..ea42b405842 100644 --- a/packages/shared/src/validators/instance.ts +++ b/packages/shared/src/validators/instance.ts @@ -51,6 +51,7 @@ export const instanceExperimentalSettingsSchema = z.object({ enableCloudSync: z.boolean().default(false), enableExternalObjects: z.boolean().default(false), enableBuiltInAgents: z.boolean().default(false), + enableDecisions: z.boolean().default(false), enableGoalsSidebarLink: z.boolean().default(false), enableServerInfoDebugView: z.boolean().default(false), autoRestartDevServerWhenIdle: z.boolean().default(false), diff --git a/server/src/__tests__/instance-settings-service.test.ts b/server/src/__tests__/instance-settings-service.test.ts index 089a2877e81..40521e70012 100644 --- a/server/src/__tests__/instance-settings-service.test.ts +++ b/server/src/__tests__/instance-settings-service.test.ts @@ -32,6 +32,7 @@ describe("instance settings service", () => { enableTaskWatchdogs: true, enableCloudSync: true, enableBuiltInAgents: true, + enableDecisions: false, enableGoalsSidebarLink: true, enableServerInfoDebugView: true, autoRestartDevServerWhenIdle: true, @@ -76,6 +77,14 @@ describe("instance settings service", () => { ).toBe(false); }); + it("defaults enableDecisions to false for empty and legacy stored settings", () => { + expect(normalizeExperimentalSettings(undefined).enableDecisions).toBe(false); + expect(normalizeExperimentalSettings({}).enableDecisions).toBe(false); + expect( + normalizeExperimentalSettings({ enableStreamlinedLeftNavigation: true }).enableDecisions, + ).toBe(false); + }); + it("defaults workspace branch repair settings to true for empty and legacy stored settings", () => { expect(normalizeExperimentalSettings(undefined).enableWorkspaceBranchReconcileForward).toBe(true); expect(normalizeExperimentalSettings({}).enableWorkspaceBranchReconcileForward).toBe(true); diff --git a/server/src/services/instance-settings.ts b/server/src/services/instance-settings.ts index 01e33d11635..d23500b5a25 100644 --- a/server/src/services/instance-settings.ts +++ b/server/src/services/instance-settings.ts @@ -56,6 +56,7 @@ export function normalizeExperimentalSettings(raw: unknown): InstanceExperimenta enableCloudSync: parsed.data.enableCloudSync ?? false, enableExternalObjects: parsed.data.enableExternalObjects ?? false, enableBuiltInAgents: parsed.data.enableBuiltInAgents ?? false, + enableDecisions: parsed.data.enableDecisions ?? false, enableGoalsSidebarLink: parsed.data.enableGoalsSidebarLink ?? false, enableServerInfoDebugView: parsed.data.enableServerInfoDebugView ?? false, autoRestartDevServerWhenIdle: parsed.data.autoRestartDevServerWhenIdle ?? false, @@ -81,6 +82,7 @@ export function normalizeExperimentalSettings(raw: unknown): InstanceExperimenta enableCloudSync: false, enableExternalObjects: false, enableBuiltInAgents: false, + enableDecisions: false, enableGoalsSidebarLink: false, enableServerInfoDebugView: false, autoRestartDevServerWhenIdle: false, diff --git a/ui/src/components/Sidebar.tsx b/ui/src/components/Sidebar.tsx index 6c5e6805e74..cf0be24e678 100644 --- a/ui/src/components/Sidebar.tsx +++ b/ui/src/components/Sidebar.tsx @@ -89,6 +89,10 @@ export function Sidebar() { const showPipelines = experimentalSettings?.enablePipelines === true; const goalsLinkPending = experimentalSettings === undefined; const showGoalsLink = experimentalSettings?.enableGoalsSidebarLink === true; + // Decisions (attention home) is an experimental surface (PAP-13481): the nav + // item is hidden entirely until the flag is enabled (same no-flash pattern as + // showWorkspacesLink — it defaults hidden, so no placeholder is needed). + const showDecisions = experimentalSettings?.enableDecisions === true; const showCases = experimentalSettings?.enableCases === true; // Streamlined left navigation (top-level Projects link + starred children) is // now the standard product sidebar (PAP-12472). The former experimental @@ -191,13 +195,6 @@ export function Sidebar() { ); })()} - 0 ? "danger" : "default"} alert={inboxBadge.failedRuns > 0} /> + {showDecisions ? ( + + ) : null} {conferenceRoomChatEnabled ? ( ) : null} diff --git a/ui/src/pages/InstanceExperimentalSettings.test.tsx b/ui/src/pages/InstanceExperimentalSettings.test.tsx index dae5805934a..eed4088986d 100644 --- a/ui/src/pages/InstanceExperimentalSettings.test.tsx +++ b/ui/src/pages/InstanceExperimentalSettings.test.tsx @@ -46,6 +46,8 @@ const TASK_WATCHDOGS_TOGGLE_SELECTOR = 'button[aria-label="Toggle task watchdogs experimental setting"]'; const GOALS_SIDEBAR_LINK_TOGGLE_SELECTOR = 'button[aria-label="Toggle goals sidebar link experimental setting"]'; +const DECISIONS_TOGGLE_SELECTOR = + 'button[aria-label="Toggle decisions experimental setting"]'; const SERVER_INFO_TOGGLE_SELECTOR = 'button[aria-label="Toggle server info debug view experimental setting"]'; const BUILT_IN_AGENTS_TOGGLE_SELECTOR = @@ -63,6 +65,7 @@ function defaultExperimentalSettings(): InstanceExperimentalSettingsPayload { enableExperimentalFileViewer: false, enableExternalObjects: false, enableBuiltInAgents: false, + enableDecisions: false, enableGoalsSidebarLink: false, enableTaskWatchdogs: false, enableCloudSync: false, @@ -225,6 +228,28 @@ describe("InstanceExperimentalSettings — Conference Room Chat card (PAP-11233) }); }); + it("renders and patches the Decisions experimental toggle", async () => { + await renderPage(); + + expect(container.textContent).toContain("Decisions"); + expect(container.textContent).toContain( + "Show the Decisions item in the main sidebar", + ); + + const toggle = container.querySelector(DECISIONS_TOGGLE_SELECTOR); + expect(toggle?.getAttribute("aria-checked")).toBe("false"); + + await act(async () => { + toggle?.click(); + }); + await flushReact(); + + expect(mockInstanceSettingsApi.updateExperimental).toHaveBeenCalledWith({ + enableDecisions: true, + }); + expect(toggle?.getAttribute("aria-checked")).toBe("true"); + }); + it("renders and patches the Goals Sidebar Link experimental toggle", async () => { await renderPage(); diff --git a/ui/src/pages/InstanceExperimentalSettings.tsx b/ui/src/pages/InstanceExperimentalSettings.tsx index 475ee16e13e..3b013e19dc4 100644 --- a/ui/src/pages/InstanceExperimentalSettings.tsx +++ b/ui/src/pages/InstanceExperimentalSettings.tsx @@ -249,6 +249,7 @@ export function InstanceExperimentalSettings() { const enableCloudSync = experimentalQuery.data?.enableCloudSync === true; const enableExternalObjects = experimentalQuery.data?.enableExternalObjects === true; const enableBuiltInAgents = experimentalQuery.data?.enableBuiltInAgents === true; + const enableDecisions = experimentalQuery.data?.enableDecisions === true; const enableGoalsSidebarLink = experimentalQuery.data?.enableGoalsSidebarLink === true; const enableCases = experimentalQuery.data?.enableCases === true; const enableServerInfoDebugView = experimentalQuery.data?.enableServerInfoDebugView === true; @@ -447,6 +448,24 @@ export function InstanceExperimentalSettings() { + +
+
+

Decisions

+

+ Show the Decisions item in the main sidebar — the attention home that surfaces the tasks awaiting your + input — while the surface is still being evaluated. +

+
+ toggleMutation.mutate({ enableDecisions: !enableDecisions })} + disabled={toggleMutation.isPending} + aria-label="Toggle decisions experimental setting" + /> +
+
+