Skip to content

Commit 0c8c9f5

Browse files
committed
feat(loops): add operations template category and sidebar alpha badge
1 parent dfdbb80 commit 0c8c9f5

2 files changed

Lines changed: 156 additions & 5 deletions

File tree

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

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ import { Flex, Heading, IconButton, Text } from "@radix-ui/themes";
1313
import { useMemo, useState } from "react";
1414
import { useLoops } from "../hooks/useLoops";
1515
import { useLoopDraftStore } from "../loopDraftStore";
16-
import { LOOP_TEMPLATES, type LoopTemplate } from "../loopTemplates";
16+
import {
17+
LOOP_TEMPLATE_CATEGORIES,
18+
LOOP_TEMPLATES,
19+
type LoopTemplate,
20+
type LoopTemplateCategory,
21+
} from "../loopTemplates";
1722
import { LoopRow } from "./LoopRow";
1823

1924
const EXAMPLE_PROMPTS = [
@@ -25,6 +30,8 @@ const EXAMPLE_PROMPTS = [
2530
export function LoopsListView() {
2631
const { data: loops, isLoading, isError, error } = useLoops();
2732
const [prompt, setPrompt] = useState("");
33+
const [templateCategory, setTemplateCategory] =
34+
useState<LoopTemplateCategory>("engineering");
2835

2936
const headerContent = useMemo(
3037
() => (
@@ -114,11 +121,31 @@ export function LoopsListView() {
114121
)}
115122

116123
<Flex direction="column" gap="3">
117-
<Text className="font-medium text-[12px] text-gray-10 uppercase tracking-wide">
118-
Start from a template
119-
</Text>
124+
<Flex align="center" justify="between" gap="3">
125+
<Text className="font-medium text-[12px] text-gray-10 uppercase tracking-wide">
126+
Start from a template
127+
</Text>
128+
<Flex className="gap-0.5 rounded-full border border-gray-5 bg-gray-2 p-0.5">
129+
{LOOP_TEMPLATE_CATEGORIES.map((option) => (
130+
<button
131+
key={option.value}
132+
type="button"
133+
onClick={() => setTemplateCategory(option.value)}
134+
className={`rounded-full px-3 py-1 text-xs transition-colors ${
135+
templateCategory === option.value
136+
? "bg-(--gray-4) text-gray-12"
137+
: "text-gray-10 hover:text-gray-12"
138+
}`}
139+
>
140+
{option.label}
141+
</button>
142+
))}
143+
</Flex>
144+
</Flex>
120145
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
121-
{LOOP_TEMPLATES.map((template) => (
146+
{LOOP_TEMPLATES.filter(
147+
(template) => template.category === templateCategory,
148+
).map((template) => (
122149
<TemplateCard
123150
key={template.id}
124151
template={template}

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

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import {
22
Bug,
3+
ChartLine,
4+
ChatCircleText,
35
GitPullRequest,
46
type Icon,
7+
Lifebuoy,
58
ListChecks,
69
NotePencil,
710
Package,
11+
Sun,
812
TestTube,
13+
Warning,
914
} from "@phosphor-icons/react";
1015
import type { LoopSchemas } from "@posthog/api-client/loops";
1116
import {
@@ -14,8 +19,19 @@ import {
1419
nextDraftTriggerKey,
1520
} from "./loopFormTypes";
1621

22+
export type LoopTemplateCategory = "engineering" | "operations";
23+
24+
export const LOOP_TEMPLATE_CATEGORIES: {
25+
value: LoopTemplateCategory;
26+
label: string;
27+
}[] = [
28+
{ value: "engineering", label: "Engineering" },
29+
{ value: "operations", label: "Operations" },
30+
];
31+
1732
export interface LoopTemplate {
1833
id: string;
34+
category: LoopTemplateCategory;
1935
icon: Icon;
2036
name: string;
2137
description: string;
@@ -51,6 +67,7 @@ function githubDraft(
5167
export const LOOP_TEMPLATES: LoopTemplate[] = [
5268
{
5369
id: "pr-review-digest",
70+
category: "engineering",
5471
icon: GitPullRequest,
5572
name: "PR review digest",
5673
description:
@@ -67,6 +84,7 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
6784
},
6885
{
6986
id: "ci-failure-summary",
87+
category: "engineering",
7088
icon: Bug,
7189
name: "CI failure summary",
7290
description:
@@ -83,6 +101,7 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
83101
},
84102
{
85103
id: "flaky-test-tracker",
104+
category: "engineering",
86105
icon: TestTube,
87106
name: "Flaky test tracker",
88107
description:
@@ -99,6 +118,7 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
99118
},
100119
{
101120
id: "dependency-update-check",
121+
category: "engineering",
102122
icon: Package,
103123
name: "Dependency update check",
104124
description:
@@ -115,6 +135,7 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
115135
},
116136
{
117137
id: "release-notes-drafter",
138+
category: "engineering",
118139
icon: NotePencil,
119140
name: "Release notes drafter",
120141
description:
@@ -131,6 +152,7 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
131152
},
132153
{
133154
id: "issue-triage",
155+
category: "engineering",
134156
icon: ListChecks,
135157
name: "Issue triage",
136158
description:
@@ -145,4 +167,106 @@ export const LOOP_TEMPLATES: LoopTemplate[] = [
145167
triggers: [githubDraft(["issues"])],
146168
}),
147169
},
170+
{
171+
id: "standup-summary",
172+
category: "operations",
173+
icon: Sun,
174+
name: "Standup summary",
175+
description:
176+
"Post a morning summary of what the team shipped yesterday and what's in progress.",
177+
triggerLabel: "Runs weekdays at 9:00",
178+
worksWith: ["GitHub", "Slack"],
179+
tone: "amber",
180+
build: () => ({
181+
name: "Standup summary",
182+
instructions:
183+
"Summarize what the team shipped yesterday (merged PRs, closed issues) and what is currently in progress. Keep it short and skimmable, then post it to the standup channel.",
184+
triggers: [scheduleDraft("0 9 * * 1-5")],
185+
}),
186+
},
187+
{
188+
id: "weekly-review",
189+
category: "operations",
190+
icon: ChartLine,
191+
name: "Weekly review",
192+
description:
193+
"A Friday summary of the week's shipped work and what's carrying into next week.",
194+
triggerLabel: "Runs Fridays at 16:00",
195+
worksWith: ["GitHub", "Slack"],
196+
tone: "blue",
197+
build: () => ({
198+
name: "Weekly review",
199+
instructions:
200+
"Write a review of the week: the PRs merged, issues closed, and notable changes, plus what is still open and carrying into next week. Post it to the team channel.",
201+
triggers: [scheduleDraft("0 16 * * 5")],
202+
}),
203+
},
204+
{
205+
id: "support-ticket-triage",
206+
category: "operations",
207+
icon: Lifebuoy,
208+
name: "Support ticket triage",
209+
description:
210+
"Triage new support tickets: categorize, set priority, and draft a reply for approval.",
211+
triggerLabel: "Runs every hour",
212+
worksWith: ["Linear", "Slack"],
213+
tone: "teal",
214+
build: () => ({
215+
name: "Support ticket triage",
216+
instructions:
217+
"Review support tickets opened since the last run. Categorize each, set a priority, link any related issue, and draft a reply for a human to approve before it's sent.",
218+
triggers: [scheduleDraft("0 * * * *")],
219+
}),
220+
},
221+
{
222+
id: "incident-digest",
223+
category: "operations",
224+
icon: Warning,
225+
name: "Incident digest",
226+
description:
227+
"Summarize open incidents and alerts and their current status each morning.",
228+
triggerLabel: "Runs daily at 8:00",
229+
worksWith: ["Sentry", "Slack"],
230+
tone: "red",
231+
build: () => ({
232+
name: "Incident digest",
233+
instructions:
234+
"Summarize the open incidents and active alerts, their severity, and current status. Flag anything that has been open too long, then post the digest to the on-call channel.",
235+
triggers: [scheduleDraft("0 8 * * *")],
236+
}),
237+
},
238+
{
239+
id: "metrics-digest",
240+
category: "operations",
241+
icon: ChartLine,
242+
name: "Metrics digest",
243+
description:
244+
"Summarize key product metrics week over week and flag notable changes.",
245+
triggerLabel: "Runs Mondays at 9:00",
246+
worksWith: ["PostHog", "Slack"],
247+
tone: "purple",
248+
build: () => ({
249+
name: "Metrics digest",
250+
instructions:
251+
"Pull the key product metrics for the last week, compare them to the prior week, and call out anything that moved notably. Post a short digest to the team channel.",
252+
triggers: [scheduleDraft("0 9 * * 1")],
253+
}),
254+
},
255+
{
256+
id: "changelog-drafter",
257+
category: "operations",
258+
icon: ChatCircleText,
259+
name: "Changelog drafter",
260+
description:
261+
"Draft a weekly customer-facing changelog from the changes that shipped.",
262+
triggerLabel: "Runs Fridays at 15:00",
263+
worksWith: ["GitHub"],
264+
tone: "green",
265+
build: () => ({
266+
name: "Changelog drafter",
267+
instructions:
268+
"From the pull requests merged this week, draft a customer-facing changelog: group related changes, write plain-language entries, and leave anything internal out. Save it as a draft for review.",
269+
triggers: [scheduleDraft("0 15 * * 5")],
270+
}),
271+
},
148272
];

0 commit comments

Comments
 (0)