From 05b90eaa2be0deeec61cc303710db81060ec3618 Mon Sep 17 00:00:00 2001 From: "roomote-roomote[bot]" <301996811+roomote-roomote[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 16:03:55 -0400 Subject: [PATCH 1/6] [Fix] License sync drops retries and custom automations cannot run on demand (#1065) Co-authored-by: Matt Rubens <2600+mrubens@users.noreply.github.com> --- ...AutomationsSettings.render.client.test.tsx | 29 +++++++++- .../automations/CustomAutomationsSection.tsx | 45 ++++++++++++++- .../src/__tests__/license-cloud.test.ts | 56 ++++++++++++++++++- .../telemetry/src/server/license-cloud.ts | 29 +++++++--- 4 files changed, 144 insertions(+), 15 deletions(-) diff --git a/apps/web/src/components/settings/automations/AutomationsSettings.render.client.test.tsx b/apps/web/src/components/settings/automations/AutomationsSettings.render.client.test.tsx index eede21ef9..2798b8fc7 100644 --- a/apps/web/src/components/settings/automations/AutomationsSettings.render.client.test.tsx +++ b/apps/web/src/components/settings/automations/AutomationsSettings.render.client.test.tsx @@ -241,6 +241,7 @@ const mutations = vi.hoisted(() => ({ connectSlack: vi.fn(), updateSettings: vi.fn(), triggerAgent: vi.fn(), + triggerCustomAutomation: vi.fn(), latestSettingsOptions: null as { onSuccess?: ( result: NonNullable, @@ -359,11 +360,16 @@ vi.mock('@tanstack/react-query', () => ({ result: NonNullable, ) => void; onError?: (...args: unknown[]) => void; + mutationKind?: 'triggerCustomAutomation'; }) => { return { isPending: false, mutate: vi.fn((variables: unknown) => { - mutations.updateSettings(variables); + if (_options?.mutationKind === 'triggerCustomAutomation') { + mutations.triggerCustomAutomation(variables); + } else { + mutations.updateSettings(variables); + } }), }; }, @@ -412,7 +418,10 @@ vi.mock('@/trpc/client', () => ({ mutationOptions: (options?: Record) => options ?? {}, }, triggerCustomAutomation: { - mutationOptions: (options?: Record) => options ?? {}, + mutationOptions: (options?: Record) => ({ + ...options, + mutationKind: 'triggerCustomAutomation', + }), }, resolveCustomAutomationSchedule: { mutationOptions: (options?: Record) => options ?? {}, @@ -879,7 +888,7 @@ describe('AutomationsSettings', () => { updatedAt: new Date('2026-01-01T00:00:00Z'), }, ]; - render(); + const { rerender } = render(); expect( await screen.findByRole('switch', { @@ -891,6 +900,20 @@ describe('AutomationsSettings', () => { 'Weekly · Production · slack:#roomote-managers · Created by Ada', ), ).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: 'Run Weekly flaky-test scan now' }), + ).toBeEnabled(); + fireEvent.click( + screen.getByRole('button', { name: 'Run Weekly flaky-test scan now' }), + ); + expect(mutations.triggerCustomAutomation).toHaveBeenCalledWith({ + id: 'automation-1', + }); + state.customAutomations[0]!.enabled = false; + rerender(); + expect( + screen.getByRole('button', { name: 'Run Weekly flaky-test scan now' }), + ).toBeDisabled(); expect( screen.getByRole('button', { name: 'Configure Weekly flaky-test scan', diff --git a/apps/web/src/components/settings/automations/CustomAutomationsSection.tsx b/apps/web/src/components/settings/automations/CustomAutomationsSection.tsx index e23fff447..a85f58c48 100644 --- a/apps/web/src/components/settings/automations/CustomAutomationsSection.tsx +++ b/apps/web/src/components/settings/automations/CustomAutomationsSection.tsx @@ -24,6 +24,7 @@ import { DialogTitle, Input, Label, + Play, Plus, Select, SelectContent, @@ -284,6 +285,35 @@ export function CustomAutomationsSection() { }), ); + const triggerMutation = useMutation( + trpc.automations.triggerCustomAutomation.mutationOptions({ + onSuccess: (result) => { + switch (result.outcome) { + case 'launched': + toast.success('Custom automation started a task.', { + action: { + label: 'Open task', + onClick: () => window.open(`/task/${result.taskId}`, '_blank'), + }, + }); + break; + case 'completed': + toast.success('Custom automation ran successfully.'); + break; + case 'skipped': + toast.info(`Custom automation had nothing to do: ${result.reason}`); + break; + case 'failed': + toast.error(`Custom automation failed: ${result.error}`); + break; + } + }, + onError: (error) => { + toast.error(error.message || 'Failed to run custom automation'); + }, + }), + ); + const resolveScheduleMutation = useMutation( trpc.automations.resolveCustomAutomationSchedule.mutationOptions({ onSuccess: (result, variables) => { @@ -336,7 +366,8 @@ export function CustomAutomationsSection() { createMutation.isPending || updateMutation.isPending || deleteMutation.isPending || - toggleMutation.isPending; + toggleMutation.isPending || + triggerMutation.isPending; const closeEditor = () => { setIsCreating(false); @@ -898,6 +929,18 @@ export function CustomAutomationsSection() {

+ + +