Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit 44157f1

Browse files
authored
feat(loops): add a default trigger to new loops (#3702)
1 parent 4f60103 commit 44157f1

3 files changed

Lines changed: 27 additions & 13 deletions

File tree

packages/ui/src/features/loops/components/LoopTriggerEditor.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ import {
1818
type RecurringFrequency,
1919
} from "../loopCron";
2020
import {
21+
defaultLoopScheduleTrigger,
2122
emptyLoopApiTriggerConfig,
2223
emptyLoopGithubTriggerConfig,
2324
emptyLoopScheduleTriggerConfig,
2425
isTriggerDraftValid,
2526
type LoopTriggerDraft,
26-
nextDraftTriggerKey,
2727
} from "../loopFormTypes";
2828
import { LoopRepositoryPicker } from "./LoopRepositoryPicker";
2929

@@ -97,15 +97,7 @@ export function LoopTriggerEditor({
9797
};
9898

9999
const addTrigger = () => {
100-
onChange([
101-
...triggers,
102-
{
103-
key: nextDraftTriggerKey(),
104-
type: "schedule",
105-
enabled: true,
106-
config: emptyLoopScheduleTriggerConfig(),
107-
},
108-
]);
100+
onChange([...triggers, defaultLoopScheduleTrigger()]);
109101
};
110102

111103
return (

packages/ui/src/features/loops/loopFormTypes.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ describe("isTriggerDraftValid", () => {
9898

9999
describe("isLoopFormValid", () => {
100100
it("accepts a named form with instructions and no triggers", () => {
101-
expect(isLoopFormValid(validFormValues())).toBe(true);
101+
expect(isLoopFormValid({ ...validFormValues(), triggers: [] })).toBe(true);
102102
});
103103

104104
it.each([
@@ -128,6 +128,19 @@ describe("isLoopFormValid", () => {
128128
});
129129
});
130130

131+
describe("emptyLoopFormValues", () => {
132+
it("starts new loops with an enabled weekly schedule trigger", () => {
133+
expect(emptyLoopFormValues().triggers).toEqual([
134+
{
135+
key: expect.any(String),
136+
type: "schedule",
137+
enabled: true,
138+
config: { cron_expression: "0 9 * * 1", timezone: "UTC" },
139+
},
140+
]);
141+
});
142+
});
143+
131144
describe("normalizeLoopFormValues", () => {
132145
it("forces team visibility when a context target is set", () => {
133146
const values = {

packages/ui/src/features/loops/loopFormTypes.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export interface LoopFormValues {
4545
}
4646

4747
export function emptyLoopScheduleTriggerConfig(): LoopSchemas.LoopScheduleTriggerConfig {
48-
return { cron_expression: "0 9 * * *", timezone: "UTC" };
48+
return { cron_expression: "0 9 * * 1", timezone: "UTC" };
4949
}
5050

5151
export function emptyLoopGithubTriggerConfig(): LoopSchemas.LoopGithubTriggerConfig {
@@ -98,6 +98,15 @@ export function nextDraftTriggerKey(): string {
9898
return `draft-trigger-${draftKeySeq}`;
9999
}
100100

101+
export function defaultLoopScheduleTrigger(): LoopTriggerDraft {
102+
return {
103+
key: nextDraftTriggerKey(),
104+
type: "schedule",
105+
enabled: true,
106+
config: emptyLoopScheduleTriggerConfig(),
107+
};
108+
}
109+
101110
export function emptyLoopFormValues(): LoopFormValues {
102111
return {
103112
name: "",
@@ -108,7 +117,7 @@ export function emptyLoopFormValues(): LoopFormValues {
108117
model: "",
109118
reasoningEffort: null,
110119
repositories: [],
111-
triggers: [],
120+
triggers: [defaultLoopScheduleTrigger()],
112121
behaviors: defaultLoopBehaviors(),
113122
notifications: defaultLoopNotifications(),
114123
contextTarget: null,

0 commit comments

Comments
 (0)