Skip to content

Commit 30bacd1

Browse files
authored
feat(home): add auto-run toggle to quick actions (#2987)
1 parent 0c94a4b commit 30bacd1

4 files changed

Lines changed: 59 additions & 3 deletions

File tree

packages/core/src/workflow/schemas.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const workflowAction = z
6161
prompt: z.string().min(1).max(8_000),
6262
adapter: z.enum(["claude", "codex"]).optional(),
6363
model: z.string().min(1).optional(),
64+
auto: z.boolean().optional(),
6465
})
6566
.strict();
6667
export type WorkflowAction = z.infer<typeof workflowAction>;
@@ -90,6 +91,7 @@ export const validationDiagnostic = z
9091
"duplicate_action_id",
9192
"action_empty_prompt",
9293
"action_empty_label",
94+
"action_auto_not_bool",
9395
]),
9496
message: z.string(),
9597
situationId: situationId.optional(),

packages/ui/src/features/home/config/ActionEditorPanel.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore";
1212
import { usePreviewConfig } from "@posthog/ui/features/task-detail/hooks/usePreviewConfig";
1313
import { Combobox } from "@posthog/ui/primitives/combobox/Combobox";
1414
import type { ComboboxSearchKeys } from "@posthog/ui/primitives/combobox/useComboboxFilter";
15-
import { Card, Flex, Text, TextArea, TextField } from "@radix-ui/themes";
15+
import {
16+
Card,
17+
Flex,
18+
Switch,
19+
Text,
20+
TextArea,
21+
TextField,
22+
} from "@radix-ui/themes";
1623
import { useMemo } from "react";
1724
import { SITUATION_TONE } from "./workflowMapLayout";
1825

@@ -189,6 +196,23 @@ export function ActionEditorPanel({
189196
</Text>
190197
)}
191198
</Field>
199+
200+
<Field label="Auto-run">
201+
<Switch
202+
className="self-start"
203+
size="1"
204+
checked={action.auto ?? false}
205+
onCheckedChange={(checked) =>
206+
patch({ auto: checked || undefined })
207+
}
208+
aria-label="Auto-run this action"
209+
/>
210+
<Text className="mt-1 text-[10px] text-gray-10">
211+
{action.auto
212+
? "A cloud task starts on its own — skipped while the workstream already has a running task."
213+
: "Run automatically when a workstream enters this state."}
214+
</Text>
215+
</Field>
192216
</Card>
193217

194218
<Flex justify="between" align="center" className="mt-3">

packages/ui/src/features/home/config/SituationStation.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Plus, Sparkle } from "@phosphor-icons/react";
1+
import { Lightning, Plus, Sparkle } from "@phosphor-icons/react";
22
import {
33
SITUATIONS,
44
type SituationId,
@@ -111,7 +111,15 @@ export function SituationStation({ id, bindings }: Props) {
111111
: action.label
112112
}
113113
>
114-
<Sparkle size={9} />
114+
{action.auto ? (
115+
<Lightning
116+
size={9}
117+
weight="fill"
118+
className="text-(--amber-9)"
119+
/>
120+
) : (
121+
<Sparkle size={9} />
122+
)}
115123
<span className="truncate">{action.label || "(no label)"}</span>
116124
</button>
117125
);

packages/ui/src/features/home/stores/workflowEditorStore.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,28 @@ describe("workflowEditorStore", () => {
117117
expect(store().draft?.bindings.working[0].label).toBe("Review");
118118
expect(store().dirty).toBe(false);
119119
});
120+
121+
it("toggles the auto flag and marks dirty", () => {
122+
store().beginEdit(makeConfig({ ci_failing: [makeAction({ id: "a" })] }));
123+
store().updateAction("ci_failing", "a", { auto: true });
124+
expect(store().draft?.bindings.ci_failing[0].auto).toBe(true);
125+
expect(store().dirty).toBe(true);
126+
store().updateAction("ci_failing", "a", { auto: false });
127+
expect(store().draft?.bindings.ci_failing[0].auto).toBe(false);
128+
});
129+
130+
it("clears dirty when auto is toggled on then back off", () => {
131+
// The editor sends `checked || undefined`, so disabling clears the key
132+
// rather than writing `auto: false`. That restores the exact baseline
133+
// serialization (no `auto` key), so the dirty flag must return to false —
134+
// otherwise an enable→disable round-trip falsely prompts an unsaved-changes save.
135+
store().beginEdit(makeConfig({ ci_failing: [makeAction({ id: "a" })] }));
136+
store().updateAction("ci_failing", "a", { auto: true });
137+
expect(store().dirty).toBe(true);
138+
store().updateAction("ci_failing", "a", { auto: undefined });
139+
expect(store().draft?.bindings.ci_failing[0].auto).toBeUndefined();
140+
expect(store().dirty).toBe(false);
141+
});
120142
});
121143

122144
describe("removeAction", () => {

0 commit comments

Comments
 (0)