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() {
+
+
+