From edeeaa56518f9b9b5c5b4fe8f39bb64856e9558b Mon Sep 17 00:00:00 2001 From: Catalin Pit <25515812+catalinpit@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:00:28 +0200 Subject: [PATCH] feat: implement webhooks --- .../(dashboard)/settings/webhooks/page.tsx | 71 ++++++++ .../settings/layout/desktop-nav.tsx | 15 +- .../settings/layout/mobile-nav.tsx | 15 +- .../webhooks/create-webhook-dialog.tsx | 3 + .../webhooks/delete-webhook-dialog.tsx | 167 ++++++++++++++++++ apps/web/src/components/forms/webhook.tsx | 0 .../migration.sql | 19 ++ packages/prisma/schema.prisma | 18 ++ 8 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/app/(dashboard)/settings/webhooks/page.tsx create mode 100644 apps/web/src/components/(dashboard)/settings/webhooks/create-webhook-dialog.tsx create mode 100644 apps/web/src/components/(dashboard)/settings/webhooks/delete-webhook-dialog.tsx create mode 100644 apps/web/src/components/forms/webhook.tsx create mode 100644 packages/prisma/migrations/20240206131417_add_user_webhooks/migration.sql diff --git a/apps/web/src/app/(dashboard)/settings/webhooks/page.tsx b/apps/web/src/app/(dashboard)/settings/webhooks/page.tsx new file mode 100644 index 000000000..e7445c1d9 --- /dev/null +++ b/apps/web/src/app/(dashboard)/settings/webhooks/page.tsx @@ -0,0 +1,71 @@ +'use client'; + +import { Zap } from 'lucide-react'; + +import { Button } from '@documenso/ui/primitives/button'; + +import { SettingsHeader } from '~/components/(dashboard)/settings/layout/header'; +import { DeleteWebhookDialog } from '~/components/(dashboard)/settings/webhooks/delete-webhook-dialog'; + +export default function WebhookPage() { + // TODO: Fetch webhooks from the DB after implementing the backend + const webhooks = [ + { + id: 1, + secret: 'my-secret', + webhookUrl: 'https://example.com/webhook', + eventTriggers: ['document.created', 'document.signed'], + enabled: true, + userID: 1, + }, + ]; + + return ( +
+ + + + + {webhooks.length === 0 && ( + // TODO: Perhaps add some illustrations here to make the page more engaging +
+

+ You have no webhooks yet. Your webhooks will be shown here once you create them. +

+
+ )} + + {webhooks.length > 0 && ( +
+ {webhooks.map((webhook) => ( +
+
+
+

Webhook URL

+

{webhook.webhookUrl}

+

Event triggers

+ {webhook.eventTriggers.map((trigger, index) => ( +

+ {trigger} +

+ ))} +
+
+
+ + + + +
+
+ ))} +
+ )} +
+ ); +} diff --git a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx index c7ab61d8a..5b7a1b739 100644 --- a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx +++ b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx @@ -5,7 +5,7 @@ import type { HTMLAttributes } from 'react'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; -import { CreditCard, Lock, User, Users } from 'lucide-react'; +import { CreditCard, Lock, User, Users, Webhook } from 'lucide-react'; import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import { cn } from '@documenso/ui/lib/utils'; @@ -48,6 +48,19 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => { + + + + + + + + + )} + + + + + Delete Webhook + + + Please note that this action is irreversible. Once confirmed, your webhook will be + permanently deleted. + + + +
+ +
+ ( + + + Confirm by typing:{' '} + + {deleteMessage} + + + + + + + + )} + /> + + +
+ + + +
+
+
+
+ +
+ + ); +}; diff --git a/apps/web/src/components/forms/webhook.tsx b/apps/web/src/components/forms/webhook.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/packages/prisma/migrations/20240206131417_add_user_webhooks/migration.sql b/packages/prisma/migrations/20240206131417_add_user_webhooks/migration.sql new file mode 100644 index 000000000..7bf4e190f --- /dev/null +++ b/packages/prisma/migrations/20240206131417_add_user_webhooks/migration.sql @@ -0,0 +1,19 @@ +-- CreateEnum +CREATE TYPE "WebhookTriggerEvents" AS ENUM ('DOCUMENT_CREATED', 'DOCUMENT_SIGNED'); + +-- CreateTable +CREATE TABLE "Webhook" ( + "id" SERIAL NOT NULL, + "webhookUrl" TEXT NOT NULL, + "eventTriggers" "WebhookTriggerEvents"[], + "secret" TEXT, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "userId" INTEGER NOT NULL, + + CONSTRAINT "Webhook_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Webhook" ADD CONSTRAINT "Webhook_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 79dcdf6aa..f2ce12cab 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -47,6 +47,7 @@ model User { VerificationToken VerificationToken[] Template Template[] securityAuditLogs UserSecurityAuditLog[] + Webhooks Webhook[] @@index([email]) } @@ -94,6 +95,23 @@ model VerificationToken { user User @relation(fields: [userId], references: [id], onDelete: Cascade) } +enum WebhookTriggerEvents { + DOCUMENT_CREATED + DOCUMENT_SIGNED +} + +model Webhook { + id Int @id @default(autoincrement()) + webhookUrl String + eventTriggers WebhookTriggerEvents[] + secret String? + enabled Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) @updatedAt + userId Int + User User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + enum SubscriptionStatus { ACTIVE PAST_DUE