Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit c57d5ba

Browse files
committed
feat: add on cache purge option to webhooks
1 parent 59598e1 commit c57d5ba

File tree

5 files changed

+89
-7
lines changed

5 files changed

+89
-7
lines changed

src/pages/apps/[id]/settings/_components/FormOutboundWebhookModal.spec.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,24 @@ describe("~/pages/apps/[id]/settings/_components/FormOutboundWebhookModal", () =
3636
);
3737
};
3838

39+
describe("always", () => {
40+
beforeEach(() => {
41+
currentApp = mockApp();
42+
createWrapper({ app: currentApp });
43+
});
44+
45+
it("should contain a help button which opens the help drawer", async () => {
46+
expect(wrapper.getByText("Help")).toBeTruthy();
47+
fireEvent.click(wrapper.getByText("Help"));
48+
49+
await waitFor(() => {
50+
expect(
51+
wrapper.getByText(/Outbound webhooks are HTTP requests/)
52+
).toBeTruthy();
53+
});
54+
});
55+
});
56+
3957
describe("create", () => {
4058
beforeEach(() => {
4159
currentApp = mockApp();

src/pages/apps/[id]/settings/_components/FormOutboundWebhookModal.tsx

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import Card from "~/components/Card";
2020
import CardHeader from "~/components/CardHeader";
2121
import CardFooter from "~/components/CardFooter";
2222
import { upsertOutboundWebhook } from "../_actions/outbound_webhook_actions";
23+
import Help from "~/components/Help/Help";
2324

2425
interface Props {
2526
app: App;
@@ -283,10 +284,70 @@ export default function FormNewOutboundWebhookModal({
283284
After each failed deployment
284285
</Option>
285286
<Option value={"on_publish"}>After deployment is published</Option>
287+
<Option value={"on_cache_purge"}>After cache is purged</Option>
286288
</Select>
287289
</FormControl>
288290

289-
<CardFooter>
291+
<CardFooter sx={{ display: "flex", justifyContent: "space-between" }}>
292+
<Help
293+
title="Outbound webhooks"
294+
subtitle="Automate workflows by sending HTTP requests to external services when specific events occur in your application deployment lifecycle."
295+
>
296+
<Typography variant="subtitle1" sx={{ fontWeight: "bold", mb: 1 }}>
297+
Overview
298+
</Typography>
299+
<Typography color="text.secondary" sx={{ mb: 2 }}>
300+
Outbound webhooks are HTTP requests that are triggered by specific
301+
events in your application deployment lifecycle. You can configure
302+
the request method, headers, and payload to suit your needs.
303+
</Typography>
304+
<Typography variant="subtitle1" sx={{ fontWeight: "bold", mb: 1 }}>
305+
Events
306+
</Typography>
307+
308+
<Typography variant="subtitle1" sx={{ fontWeight: "bold", mb: 1 }}>
309+
1. After each successful deployment
310+
</Typography>
311+
<Typography color="text.secondary">
312+
The webhook will be triggered after every successful deployment of
313+
your application. A successful deployment means that your code has
314+
been built and deployed without any errors. This event cycle
315+
occurs before status checks are run.
316+
</Typography>
317+
<Typography
318+
variant="subtitle1"
319+
sx={{ fontWeight: "bold", mt: 2, mb: 1 }}
320+
>
321+
2. After each failed deployment
322+
</Typography>
323+
<Typography color="text.secondary">
324+
The webhook will be triggered after every failed deployment. This
325+
event cycle occurs before status checks are run.
326+
</Typography>
327+
<Typography
328+
variant="subtitle1"
329+
sx={{ fontWeight: "bold", mt: 2, mb: 1 }}
330+
>
331+
3.After a deployment is published
332+
</Typography>
333+
<Typography color="text.secondary">
334+
The webhook will be triggered after a deployment is published.
335+
This event cycle occurs after status checks are run.
336+
</Typography>
337+
<Typography
338+
variant="subtitle1"
339+
sx={{ fontWeight: "bold", mt: 2, mb: 1 }}
340+
>
341+
4.After a cache purge
342+
</Typography>
343+
<Typography color="text.secondary">
344+
Cache is purged after the following events:
345+
<br />
346+
<br />- A deployment is published
347+
<br />- Any operation to snippets
348+
<br />- The environment configuration is updated
349+
</Typography>
350+
</Help>
290351
<Button
291352
variant="contained"
292353
color="secondary"

src/pages/apps/[id]/settings/_components/FormOutboundWebhooks.spec.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { describe, beforeEach, it, expect } from "vitest";
12
import type { OutboundWebhook } from "../types";
23
import { fireEvent, RenderResult } from "@testing-library/react";
34
import { waitFor, render } from "@testing-library/react";
@@ -35,21 +36,21 @@ describe("~/pages/apps/[id]/settings/_components/FormOutboundWebhooks", () => {
3536
createWrapper({ app: currentApp });
3637
});
3738

38-
test("the button is at loading state initially", () => {
39+
it("the button is at loading state initially", () => {
3940
expect(wrapper.getByLabelText("Add new webhook").innerHTML).toContain(
4041
"<svg"
4142
);
4243
});
4344

44-
test("the button is not at loading state when the query has loaded", async () => {
45+
it("the button is not at loading state when the query has loaded", async () => {
4546
await waitFor(() => {
4647
expect(wrapper.getByLabelText("Add new webhook").innerHTML).not.toContain(
4748
"spinner"
4849
);
4950
});
5051
});
5152

52-
test("should handle webhook deletion", async () => {
53+
it("should handle webhook deletion", async () => {
5354
await waitFor(() => {
5455
expect(wrapper.getAllByLabelText("expand")).toHaveLength(2);
5556
});
@@ -80,7 +81,7 @@ describe("~/pages/apps/[id]/settings/_components/FormOutboundWebhooks", () => {
8081
});
8182
});
8283

83-
test("clicking add new webhook opens a modal", async () => {
84+
it("clicking add new webhook opens a modal", async () => {
8485
await waitFor(() => {
8586
expect(
8687
wrapper.getAllByText("Triggered after a deployment is published")
@@ -96,7 +97,7 @@ describe("~/pages/apps/[id]/settings/_components/FormOutboundWebhooks", () => {
9697
});
9798
});
9899

99-
test.each`
100+
it.each`
100101
description | endpoint
101102
${"short url"} | ${"https://discord.com/example/endpoint"}
102103
${"long url"} | ${"https://discord.com/api/webhooks/example/endpoint..."}

src/pages/apps/[id]/settings/_components/FormOutboundWebhooks.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const messages: Record<TriggerWhen, string> = {
2828
on_deploy_success: "Triggered after each successful deployment",
2929
on_deploy_failed: "Triggered after each failed deployment",
3030
on_publish: "Triggered after a deployment is published",
31+
on_cache_purge: "Triggered after a cache purge",
3132
};
3233

3334
const FormOutboundWebhooks: React.FC<Props> = ({ app }): React.ReactElement => {

src/pages/apps/[id]/settings/types.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export type AllowedMethod = "GET" | "POST" | "HEAD";
1818
export type TriggerWhen =
1919
| "on_deploy_success"
2020
| "on_deploy_failed"
21-
| "on_publish";
21+
| "on_publish"
22+
| "on_cache_purge";
2223

2324
export interface OutboundWebhook {
2425
id?: string;

0 commit comments

Comments
 (0)