From 1bb9293c98e744193e9bcda99837cb6947455a65 Mon Sep 17 00:00:00 2001 From: Dotta Date: Tue, 11 Aug 2026 20:22:23 +0000 Subject: [PATCH] fix(ui): save unmaterialized inbox policy Co-Authored-By: Paperclip --- .../InboxAgentPolicyControl.test.tsx | 36 ++++++++++++++++++- ui/src/components/InboxAgentPolicyControl.tsx | 11 +++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ui/src/components/InboxAgentPolicyControl.test.tsx b/ui/src/components/InboxAgentPolicyControl.test.tsx index 1450411e0d1..e3a5fd46688 100644 --- a/ui/src/components/InboxAgentPolicyControl.test.tsx +++ b/ui/src/components/InboxAgentPolicyControl.test.tsx @@ -51,7 +51,7 @@ function policy(overrides: Partial = {}): InboxAgentPolicy { userId: "user-1", mode: "open", allowedAgentIds: [], - materialized: false, + materialized: true, createdAt: null, updatedAt: null, ...overrides, @@ -127,6 +127,40 @@ describe("InboxAgentPolicyControl", () => { act(() => root.unmount()); }); + it("enables saving an unmaterialized open policy and marks it unsaved until persistence", async () => { + mockInboxAgentPolicyApi.getMine.mockResolvedValue(policy({ materialized: false })); + const root = render(container); + await flush(); + + await waitForAssertion(() => { + expect(container.textContent).toContain("Not saved yet. Agents cannot manage your inbox until you save."); + const save = Array.from(container.querySelectorAll("button")).find((button) => + button.textContent?.includes("Save"), + ); + expect(save?.disabled).toBe(false); + }); + + const saveButton = Array.from(container.querySelectorAll("button")).find((button) => + button.textContent?.includes("Save"), + ); + expect(saveButton).toBeTruthy(); + await act(async () => saveButton!.click()); + await flush(); + + expect(mockInboxAgentPolicyApi.updateMine).toHaveBeenCalledWith("company-1", { + mode: "open", + allowedAgentIds: [], + }); + + await waitForAssertion(() => { + expect(container.textContent).not.toContain("Not saved yet"); + expect(container.textContent).toContain("Saved"); + expect(saveButton!.disabled).toBe(true); + }); + + act(() => root.unmount()); + }); + it("round-trips an allowlist selection through the PUT endpoint", async () => { const root = render(container); await flush(); diff --git a/ui/src/components/InboxAgentPolicyControl.tsx b/ui/src/components/InboxAgentPolicyControl.tsx index 5570683432b..2e321546bc4 100644 --- a/ui/src/components/InboxAgentPolicyControl.tsx +++ b/ui/src/components/InboxAgentPolicyControl.tsx @@ -94,7 +94,10 @@ export function InboxAgentPolicyControl({ companyId }: { companyId: string | nul }); const isDirty = Boolean( - draft && policy && policyKey(draft.mode, draft.allowedAgentIds) !== policyKey(policy.mode, policy.allowedAgentIds), + draft && + policy && + (!policy.materialized || + policyKey(draft.mode, draft.allowedAgentIds) !== policyKey(policy.mode, policy.allowedAgentIds)), ); if (policyQuery.error) { @@ -140,6 +143,12 @@ export function InboxAgentPolicyControl({ companyId }: { companyId: string | nul className="max-w-2xl" /> + {!policy.materialized ? ( +

+ Not saved yet. Agents cannot manage your inbox until you save. +

+ ) : null} + {draft.mode === "allowlist" ? (
Agents allowed to tidy my inbox