feat: support team webhooks

This commit is contained in:
Mythie
2024-02-27 16:56:32 +11:00
parent 7dd2bbd8ab
commit a4b1f7c983
15 changed files with 505 additions and 29 deletions

View File

@ -10,7 +10,7 @@ import { useForm } from 'react-hook-form';
import type { z } from 'zod';
import { trpc } from '@documenso/trpc/react';
import { ZCreateWebhookFormSchema } from '@documenso/trpc/server/webhook-router/schema';
import { ZCreateWebhookMutationSchema } from '@documenso/trpc/server/webhook-router/schema';
import { Button } from '@documenso/ui/primitives/button';
import {
Dialog,
@ -35,8 +35,12 @@ import { PasswordInput } from '@documenso/ui/primitives/password-input';
import { Switch } from '@documenso/ui/primitives/switch';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { useOptionalCurrentTeam } from '~/providers/team';
import { TriggerMultiSelectCombobox } from './trigger-multiselect-combobox';
const ZCreateWebhookFormSchema = ZCreateWebhookMutationSchema.omit({ teamId: true });
type TCreateWebhookFormSchema = z.infer<typeof ZCreateWebhookFormSchema>;
export type CreateWebhookDialogProps = {
@ -46,6 +50,9 @@ export type CreateWebhookDialogProps = {
export const CreateWebhookDialog = ({ trigger, ...props }: CreateWebhookDialogProps) => {
const router = useRouter();
const { toast } = useToast();
const team = useOptionalCurrentTeam();
const [open, setOpen] = useState(false);
const form = useForm<TCreateWebhookFormSchema>({
@ -60,9 +67,20 @@ export const CreateWebhookDialog = ({ trigger, ...props }: CreateWebhookDialogPr
const { mutateAsync: createWebhook } = trpc.webhook.createWebhook.useMutation();
const onSubmit = async (values: TCreateWebhookFormSchema) => {
const onSubmit = async ({
enabled,
eventTriggers,
secret,
webhookUrl,
}: TCreateWebhookFormSchema) => {
try {
await createWebhook(values);
await createWebhook({
enabled,
eventTriggers,
secret,
webhookUrl,
teamId: team?.id,
});
setOpen(false);

View File

@ -31,6 +31,8 @@ import {
import { Input } from '@documenso/ui/primitives/input';
import { useToast } from '@documenso/ui/primitives/use-toast';
import { useOptionalCurrentTeam } from '~/providers/team';
export type DeleteWebhookDialogProps = {
webhook: Pick<Webhook, 'id' | 'webhookUrl'>;
onDelete?: () => void;
@ -40,6 +42,9 @@ export type DeleteWebhookDialogProps = {
export const DeleteWebhookDialog = ({ webhook, children }: DeleteWebhookDialogProps) => {
const router = useRouter();
const { toast } = useToast();
const team = useOptionalCurrentTeam();
const [open, setOpen] = useState(false);
const deleteMessage = `delete ${webhook.webhookUrl}`;
@ -63,7 +68,7 @@ export const DeleteWebhookDialog = ({ webhook, children }: DeleteWebhookDialogPr
const onSubmit = async () => {
try {
await deleteWebhook({ id: webhook.id });
await deleteWebhook({ id: webhook.id, teamId: team?.id });
toast({
title: 'Webhook deleted',

View File

@ -5,7 +5,7 @@ import type { HTMLAttributes } from 'react';
import Link from 'next/link';
import { useParams, usePathname } from 'next/navigation';
import { Braces, CreditCard, Settings, Users } from 'lucide-react';
import { Braces, CreditCard, Settings, Users, Webhook } from 'lucide-react';
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { cn } from '@documenso/ui/lib/utils';
@ -22,6 +22,7 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
const settingsPath = `/t/${teamUrl}/settings`;
const membersPath = `/t/${teamUrl}/settings/members`;
const tokensPath = `/t/${teamUrl}/settings/tokens`;
const webhooksPath = `/t/${teamUrl}/settings/webhooks`;
const billingPath = `/t/${teamUrl}/settings/billing`;
return (
@ -59,6 +60,19 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => {
</Button>
</Link>
<Link href={webhooksPath}>
<Button
variant="ghost"
className={cn(
'w-full justify-start',
pathname?.startsWith(webhooksPath) && 'bg-secondary',
)}
>
<Webhook className="mr-2 h-5 w-5" />
Webhooks
</Button>
</Link>
{IS_BILLING_ENABLED() && (
<Link href={billingPath}>
<Button

View File

@ -5,7 +5,7 @@ import type { HTMLAttributes } from 'react';
import Link from 'next/link';
import { useParams, usePathname } from 'next/navigation';
import { Braces, CreditCard, Key, User } from 'lucide-react';
import { Braces, CreditCard, Key, User, Webhook } from 'lucide-react';
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { cn } from '@documenso/ui/lib/utils';
@ -22,6 +22,7 @@ export const MobileNav = ({ className, ...props }: MobileNavProps) => {
const settingsPath = `/t/${teamUrl}/settings`;
const membersPath = `/t/${teamUrl}/settings/members`;
const tokensPath = `/t/${teamUrl}/settings/tokens`;
const webhooksPath = `/t/${teamUrl}/settings/webhooks`;
const billingPath = `/t/${teamUrl}/settings/billing`;
return (
@ -67,6 +68,19 @@ export const MobileNav = ({ className, ...props }: MobileNavProps) => {
</Button>
</Link>
<Link href={webhooksPath}>
<Button
variant="ghost"
className={cn(
'w-full justify-start',
pathname?.startsWith(webhooksPath) && 'bg-secondary',
)}
>
<Webhook className="mr-2 h-5 w-5" />
Webhooks
</Button>
</Link>
{IS_BILLING_ENABLED() && (
<Link href={billingPath}>
<Button