diff --git a/apps/web/modules/webhooks/components/EventTypeWebhookListItem.tsx b/apps/web/modules/webhooks/components/EventTypeWebhookListItem.tsx
index 49f0b72fa1..5eb0b4e43f 100644
--- a/apps/web/modules/webhooks/components/EventTypeWebhookListItem.tsx
+++ b/apps/web/modules/webhooks/components/EventTypeWebhookListItem.tsx
@@ -1,5 +1,7 @@
"use client";
+import { useState } from "react";
+
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
@@ -19,6 +21,8 @@ import { showToast } from "@calcom/ui/components/toast";
import { Tooltip } from "@calcom/ui/components/tooltip";
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
+import { DeleteWebhookDialog } from "./dialogs/DeleteWebhookDialog";
+
type WebhookProps = {
id: string;
subscriberUrl: string;
@@ -39,6 +43,7 @@ export default function EventTypeWebhookListItem(props: {
const { t } = useLocale();
const utils = trpc.useUtils();
const { webhook } = props;
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const deleteWebhook = trpc.viewer.webhook.delete.useMutation({
async onSuccess() {
@@ -47,12 +52,16 @@ export default function EventTypeWebhookListItem(props: {
await utils.viewer.webhook.getByViewer.invalidate();
await utils.viewer.webhook.list.invalidate();
await utils.viewer.eventTypes.get.invalidate();
+ setDeleteDialogOpen(false);
+ },
+ onError() {
+ showToast(t("something_went_wrong"), "error");
+ setDeleteDialogOpen(false);
},
});
const toggleWebhook = trpc.viewer.webhook.edit.useMutation({
async onSuccess(data) {
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
- // TODO: Better success message
showToast(t(data?.active ? "enabled" : "disabled"), "success");
await utils.viewer.webhook.getByViewer.invalidate();
await utils.viewer.webhook.list.invalidate();
@@ -60,15 +69,6 @@ export default function EventTypeWebhookListItem(props: {
},
});
- const onDeleteWebhook = () => {
- // TODO: Confimation dialog before deleting
- deleteWebhook.mutate({
- id: webhook.id,
- eventTypeId: webhook.eventTypeId || undefined,
- teamId: webhook.teamId || undefined,
- });
- };
-
return (
setDeleteDialogOpen(true)}
+ disabled={deleteWebhook.isPending}
/>
@@ -146,7 +148,11 @@ export default function EventTypeWebhookListItem(props: {
-
+ setDeleteDialogOpen(true)}
+ disabled={deleteWebhook.isPending}>
{t("delete")}
@@ -154,6 +160,19 @@ export default function EventTypeWebhookListItem(props: {
)}
+
+ {
+ deleteWebhook.mutate({
+ id: webhook.id,
+ eventTypeId: webhook.eventTypeId || undefined,
+ teamId: webhook.teamId || undefined,
+ });
+ }}
+ />
);
}
diff --git a/apps/web/modules/webhooks/components/WebhookListItem.tsx b/apps/web/modules/webhooks/components/WebhookListItem.tsx
index be795d8163..656b9d0adc 100644
--- a/apps/web/modules/webhooks/components/WebhookListItem.tsx
+++ b/apps/web/modules/webhooks/components/WebhookListItem.tsx
@@ -1,5 +1,8 @@
"use client";
+import Link from "next/link";
+import { useState } from "react";
+
import { getWebhookVersionDocsUrl, getWebhookVersionLabel } from "@calcom/features/webhooks/lib/constants";
import type { Webhook } from "@calcom/features/webhooks/lib/dto/types";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -21,7 +24,8 @@ import { showToast } from "@calcom/ui/components/toast";
import { Tooltip } from "@calcom/ui/components/tooltip";
import { revalidateEventTypeEditPage } from "@calcom/web/app/(use-page-wrapper)/event-types/[type]/actions";
import { revalidateWebhooksList } from "@calcom/web/app/(use-page-wrapper)/settings/(settings-layout)/developer/webhooks/(with-loader)/actions";
-import Link from "next/link";
+
+import { DeleteWebhookDialog } from "./dialogs/DeleteWebhookDialog";
const MAX_BADGES_TWO_ROWS = 8; // Approximately 2 rows of badges
@@ -38,6 +42,7 @@ export default function WebhookListItem(props: {
const { t } = useLocale();
const utils = trpc.useUtils();
const { webhook } = props;
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const deleteWebhook = trpc.viewer.webhook.delete.useMutation({
async onSuccess() {
@@ -47,13 +52,17 @@ export default function WebhookListItem(props: {
await utils.viewer.webhook.getByViewer.invalidate();
await utils.viewer.webhook.list.invalidate();
await utils.viewer.eventTypes.get.invalidate();
+ setDeleteDialogOpen(false);
+ },
+ onError() {
+ showToast(t("something_went_wrong"), "error");
+ setDeleteDialogOpen(false);
},
});
const toggleWebhook = trpc.viewer.webhook.edit.useMutation({
async onSuccess(data) {
if (webhook.eventTypeId) revalidateEventTypeEditPage(webhook.eventTypeId);
revalidateWebhooksList();
- // TODO: Better success message
showToast(t(data?.active ? "enabled" : "disabled"), "success");
await utils.viewer.webhook.getByViewer.invalidate();
await utils.viewer.webhook.list.invalidate();
@@ -61,17 +70,9 @@ export default function WebhookListItem(props: {
},
});
- const onDeleteWebhook = () => {
- // TODO: Confimation dialog before deleting
- deleteWebhook.mutate({
- id: webhook.id,
- eventTypeId: webhook.eventTypeId || undefined,
- teamId: webhook.teamId || undefined,
- });
- };
-
return (
setDeleteDialogOpen(true)}
+ disabled={deleteWebhook.isPending}
/>
)}
@@ -187,7 +190,11 @@ export default function WebhookListItem(props: {
{props.permissions.canDeleteWebhook && (
-
+ setDeleteDialogOpen(true)}
+ disabled={deleteWebhook.isPending}>
{t("delete")}
@@ -196,6 +203,19 @@ export default function WebhookListItem(props: {
)}
+
+ {
+ deleteWebhook.mutate({
+ id: webhook.id,
+ eventTypeId: webhook.eventTypeId || undefined,
+ teamId: webhook.teamId || undefined,
+ });
+ }}
+ />
);
}
diff --git a/apps/web/modules/webhooks/components/dialogs/DeleteWebhookDialog.tsx b/apps/web/modules/webhooks/components/dialogs/DeleteWebhookDialog.tsx
new file mode 100644
index 0000000000..4511d8b146
--- /dev/null
+++ b/apps/web/modules/webhooks/components/dialogs/DeleteWebhookDialog.tsx
@@ -0,0 +1,31 @@
+import { APP_NAME } from "@calcom/lib/constants";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { Dialog, ConfirmationDialogContent } from "@calcom/ui/components/dialog";
+
+interface DeleteWebhookDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ onConfirm: () => void;
+ isPending: boolean;
+}
+
+export function DeleteWebhookDialog({ open, onOpenChange, onConfirm, isPending }: DeleteWebhookDialogProps) {
+ const { t } = useLocale();
+
+ return (
+
+ );
+}
diff --git a/apps/web/playwright/webhook.e2e.ts b/apps/web/playwright/webhook.e2e.ts
index c2705e5a75..c1701a0f10 100644
--- a/apps/web/playwright/webhook.e2e.ts
+++ b/apps/web/playwright/webhook.e2e.ts
@@ -876,3 +876,35 @@ test.describe("OOO_CREATED", async () => {
webhookReceiver.close();
});
});
+
+test.describe("Webhook deletion", async () => {
+ test("shows confirmation dialog and deletes webhook on confirm", async ({ page, users }) => {
+ const user = await users.create();
+ await user.apiLogin();
+
+ await page.goto("/settings/developer/webhooks");
+ await page.click('[data-testid="new_webhook"]');
+ await page.fill('[name="subscriberUrl"]', "https://example.com/test-webhook");
+
+ await Promise.all([
+ page.click("[type=submit]"),
+ page.waitForURL((url) => url.pathname.endsWith("/settings/developer/webhooks")),
+ ]);
+
+ const webhookListItem = page.getByTestId("webhook-list-item");
+ await expect(webhookListItem).toBeVisible();
+
+ const deleteButton = page.getByTestId("delete-webhook");
+ await expect(deleteButton).toBeVisible();
+ await deleteButton.click();
+
+ await expect(page.getByTestId("dialog-confirmation")).toBeVisible();
+
+ const deleteResponsePromise = page.waitForResponse((res) => res.url().includes("/api/trpc/webhook/delete"));
+ await page.getByTestId("dialog-confirmation").click();
+ const deleteResponse = await deleteResponsePromise;
+ expect(deleteResponse.ok()).toBe(true);
+
+ await expect(webhookListItem).not.toBeVisible();
+ });
+});
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index 13af35248e..e146e10b3b 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -254,7 +254,7 @@
"hey_there": "Hey there",
"there": "there",
"forgot_your_password_calcom": "Forgot your password? - {{appName}}",
- "delete_webhook_confirmation_message": "Are you sure you want to delete this webhook? You will no longer receive {{appName}} meeting data at a specified URL, in real-time, when an event is scheduled or canceled.",
+ "delete_webhook_confirmation_message": "Are you sure you want to delete this webhook? You will no longer receive {{appName}} data at the specified URL for your configured event triggers.",
"confirm_delete_webhook": "Delete webhook",
"edit_webhook": "Edit webhook",
"delete_webhook": "Delete webhook",