From 1126fe4bff9d1f48ec77b576ece303164e72ed9a Mon Sep 17 00:00:00 2001
From: Adithya Krishna
Date: Wed, 17 Apr 2024 03:52:59 +0530
Subject: [PATCH 01/13] chore: added filename extension check
---
packages/lib/server-only/document/send-completed-email.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/lib/server-only/document/send-completed-email.ts b/packages/lib/server-only/document/send-completed-email.ts
index a397e47e7..f5cef426c 100644
--- a/packages/lib/server-only/document/send-completed-email.ts
+++ b/packages/lib/server-only/document/send-completed-email.ts
@@ -80,7 +80,7 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
text: render(template, { plainText: true }),
attachments: [
{
- filename: document.title,
+ filename: document.title.endsWith('.pdf') ? document.title : document.title + '.pdf',
content: Buffer.from(completedDocument),
},
],
From f8ddb0f9225e5c63a74377f71ab6e65d94ebbbe7 Mon Sep 17 00:00:00 2001
From: Adithya Krishna
Date: Thu, 18 Apr 2024 18:12:08 +0530
Subject: [PATCH 02/13] chore: update filename for bulk recipients
---
packages/lib/server-only/document/send-completed-email.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/lib/server-only/document/send-completed-email.ts b/packages/lib/server-only/document/send-completed-email.ts
index f5cef426c..f841aef33 100644
--- a/packages/lib/server-only/document/send-completed-email.ts
+++ b/packages/lib/server-only/document/send-completed-email.ts
@@ -130,7 +130,7 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
text: render(template, { plainText: true }),
attachments: [
{
- filename: document.title,
+ filename: document.title.endsWith('.pdf') ? document.title : document.title + '.pdf',
content: Buffer.from(completedDocument),
},
],
From 6526377f1bd51d19b9e5677bd67c11cd612e5ddb Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Thu, 18 Apr 2024 21:56:31 +0700
Subject: [PATCH 03/13] feat: add visible completed fields
---
.../documents/[id]/document-page-view.tsx | 24 ++-
.../src/app/(signing)/sign/[token]/page.tsx | 11 +-
.../sign/[token]/signing-page-view.tsx | 12 +-
.../avatar/stack-avatars-with-tooltip.tsx | 156 ++++++------------
.../document/document-read-only-fields.tsx | 113 +++++++++++++
.../get-completed-fields-for-document.ts | 29 ++++
.../field/get-completed-fields-for-token.ts | 33 ++++
.../template/create-document-from-template.ts | 6 +-
.../template/duplicate-template.ts | 6 +-
packages/lib/types/fields.ts | 3 +
.../migration.sql | 8 +
packages/prisma/schema.prisma | 4 +-
packages/ui/components/field/field.tsx | 4 +-
packages/ui/primitives/popover.tsx | 64 ++++++-
14 files changed, 356 insertions(+), 117 deletions(-)
create mode 100644 apps/web/src/components/document/document-read-only-fields.tsx
create mode 100644 packages/lib/server-only/field/get-completed-fields-for-document.ts
create mode 100644 packages/lib/server-only/field/get-completed-fields-for-token.ts
create mode 100644 packages/lib/types/fields.ts
create mode 100644 packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx b/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
index e20c88a27..3b89f63f5 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
@@ -8,6 +8,7 @@ import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
import { getServerComponentFlag } from '@documenso/lib/server-only/feature-flags/get-server-component-feature-flag';
+import { getCompletedFieldsForDocument } from '@documenso/lib/server-only/field/get-completed-fields-for-document';
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
@@ -19,6 +20,7 @@ import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip';
import { DocumentHistorySheet } from '~/components/document/document-history-sheet';
+import { DocumentReadOnlyFields } from '~/components/document/document-read-only-fields';
import {
DocumentStatus as DocumentStatusComponent,
FRIENDLY_STATUS_MAP,
@@ -83,11 +85,16 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
documentMeta.password = securePassword;
}
- const recipients = await getRecipientsForDocument({
- documentId,
- teamId: team?.id,
- userId: user.id,
- });
+ const [recipients, completedFields] = await Promise.all([
+ getRecipientsForDocument({
+ documentId,
+ teamId: team?.id,
+ userId: user.id,
+ }),
+ getCompletedFieldsForDocument({
+ documentId,
+ }),
+ ]);
const documentWithRecipients = {
...document,
@@ -148,6 +155,13 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
+ {document.status === DocumentStatus.PENDING && (
+
+ )}
+
diff --git a/apps/web/src/app/(signing)/sign/[token]/page.tsx b/apps/web/src/app/(signing)/sign/[token]/page.tsx
index e83f675ce..95c9b6512 100644
--- a/apps/web/src/app/(signing)/sign/[token]/page.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/page.tsx
@@ -6,6 +6,7 @@ import { getServerComponentSession } from '@documenso/lib/next-auth/get-server-c
import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token';
import { isRecipientAuthorized } from '@documenso/lib/server-only/document/is-recipient-authorized';
import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document';
+import { getCompletedFieldsForToken } from '@documenso/lib/server-only/field/get-completed-fields-for-token';
import { getFieldsForToken } from '@documenso/lib/server-only/field/get-fields-for-token';
import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token';
import { getRecipientSignatures } from '@documenso/lib/server-only/recipient/get-recipient-signatures';
@@ -37,7 +38,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
const requestMetadata = extractNextHeaderRequestMetadata(requestHeaders);
- const [document, fields, recipient] = await Promise.all([
+ const [document, fields, recipient, completedFields] = await Promise.all([
getDocumentAndSenderByToken({
token,
userId: user?.id,
@@ -45,6 +46,7 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
}).catch(() => null),
getFieldsForToken({ token }),
getRecipientByToken({ token }).catch(() => null),
+ getCompletedFieldsForToken({ token }),
]);
if (!document || !document.documentData || !recipient) {
@@ -120,7 +122,12 @@ export default async function SigningPage({ params: { token } }: SigningPageProp
signature={user?.email === recipient.email ? user.signature : undefined}
>
-
+
);
diff --git a/apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx b/apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx
index c04679956..4691d0d4c 100644
--- a/apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/signing-page-view.tsx
@@ -4,12 +4,14 @@ import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-form
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
import type { DocumentAndSender } from '@documenso/lib/server-only/document/get-document-by-token';
+import type { CompletedField } from '@documenso/lib/types/fields';
import type { Field, Recipient } from '@documenso/prisma/client';
import { FieldType, RecipientRole } from '@documenso/prisma/client';
import { Card, CardContent } from '@documenso/ui/primitives/card';
import { ElementVisible } from '@documenso/ui/primitives/element-visible';
import { LazyPDFViewer } from '@documenso/ui/primitives/lazy-pdf-viewer';
+import { DocumentReadOnlyFields } from '~/components/document/document-read-only-fields';
import { truncateTitle } from '~/helpers/truncate-title';
import { DateField } from './date-field';
@@ -23,9 +25,15 @@ export type SigningPageViewProps = {
document: DocumentAndSender;
recipient: Recipient;
fields: Field[];
+ completedFields: CompletedField[];
};
-export const SigningPageView = ({ document, recipient, fields }: SigningPageViewProps) => {
+export const SigningPageView = ({
+ document,
+ recipient,
+ fields,
+ completedFields,
+}: SigningPageViewProps) => {
const truncatedTitle = truncateTitle(document.title);
const { documentData, documentMeta } = document;
@@ -70,6 +78,8 @@ export const SigningPageView = ({ document, recipient, fields }: SigningPageView
+
+
{fields.map((field) =>
match(field.type)
diff --git a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx
index 10f7d1e6a..b6a13b911 100644
--- a/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx
+++ b/apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx
@@ -1,12 +1,10 @@
'use client';
-import { useRef, useState } from 'react';
-
import { getRecipientType } from '@documenso/lib/client-only/recipient-type';
import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
import type { Recipient } from '@documenso/prisma/client';
-import { Popover, PopoverContent, PopoverTrigger } from '@documenso/ui/primitives/popover';
+import { PopoverHover } from '@documenso/ui/primitives/popover';
import { AvatarWithRecipient } from './avatar-with-recipient';
import { StackAvatar } from './stack-avatar';
@@ -23,11 +21,6 @@ export const StackAvatarsWithTooltip = ({
position,
children,
}: StackAvatarsWithTooltipProps) => {
- const [open, setOpen] = useState(false);
-
- const isControlled = useRef(false);
- const isMouseOverTimeout = useRef(null);
-
const waitingRecipients = recipients.filter(
(recipient) => getRecipientType(recipient) === 'waiting',
);
@@ -44,105 +37,62 @@ export const StackAvatarsWithTooltip = ({
(recipient) => getRecipientType(recipient) === 'unsigned',
);
- const onMouseEnter = () => {
- if (isMouseOverTimeout.current) {
- clearTimeout(isMouseOverTimeout.current);
- }
-
- if (isControlled.current) {
- return;
- }
-
- isMouseOverTimeout.current = setTimeout(() => {
- setOpen((o) => (!o ? true : o));
- }, 200);
- };
-
- const onMouseLeave = () => {
- if (isMouseOverTimeout.current) {
- clearTimeout(isMouseOverTimeout.current);
- }
-
- if (isControlled.current) {
- return;
- }
-
- setTimeout(() => {
- setOpen((o) => (o ? false : o));
- }, 200);
- };
-
- const onOpenChange = (newOpen: boolean) => {
- isControlled.current = newOpen;
-
- setOpen(newOpen);
- };
-
return (
-
-
- {children || }
-
-
-
- {completedRecipients.length > 0 && (
-
-
Completed
- {completedRecipients.map((recipient: Recipient) => (
-
-
-
-
{recipient.email}
-
- {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName}
-
-
+
}
+ contentProps={{
+ className: 'flex flex-col gap-y-5 py-2',
+ side: position,
+ }}
+ >
+ {completedRecipients.length > 0 && (
+
+
Completed
+ {completedRecipients.map((recipient: Recipient) => (
+
+
+
+
{recipient.email}
+
+ {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName}
+
- ))}
-
- )}
+
+ ))}
+
+ )}
- {waitingRecipients.length > 0 && (
-
-
Waiting
- {waitingRecipients.map((recipient: Recipient) => (
-
- ))}
-
- )}
+ {waitingRecipients.length > 0 && (
+
+
Waiting
+ {waitingRecipients.map((recipient: Recipient) => (
+
+ ))}
+
+ )}
- {openedRecipients.length > 0 && (
-
-
Opened
- {openedRecipients.map((recipient: Recipient) => (
-
- ))}
-
- )}
+ {openedRecipients.length > 0 && (
+
+
Opened
+ {openedRecipients.map((recipient: Recipient) => (
+
+ ))}
+
+ )}
- {uncompletedRecipients.length > 0 && (
-
-
Uncompleted
- {uncompletedRecipients.map((recipient: Recipient) => (
-
- ))}
-
- )}
-
-
+ {uncompletedRecipients.length > 0 && (
+
+
Uncompleted
+ {uncompletedRecipients.map((recipient: Recipient) => (
+
+ ))}
+
+ )}
+
);
};
diff --git a/apps/web/src/components/document/document-read-only-fields.tsx b/apps/web/src/components/document/document-read-only-fields.tsx
new file mode 100644
index 000000000..530066fa8
--- /dev/null
+++ b/apps/web/src/components/document/document-read-only-fields.tsx
@@ -0,0 +1,113 @@
+'use client';
+
+import { useState } from 'react';
+
+import { P, match } from 'ts-pattern';
+
+import {
+ DEFAULT_DOCUMENT_DATE_FORMAT,
+ convertToLocalSystemFormat,
+} from '@documenso/lib/constants/date-formats';
+import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
+import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
+import type { CompletedField } from '@documenso/lib/types/fields';
+import { extractInitials } from '@documenso/lib/utils/recipient-formatter';
+import type { DocumentMeta } from '@documenso/prisma/client';
+import { FieldType } from '@documenso/prisma/client';
+import { FieldRootContainer } from '@documenso/ui/components/field/field';
+import { Avatar, AvatarFallback } from '@documenso/ui/primitives/avatar';
+import { Button } from '@documenso/ui/primitives/button';
+import { FRIENDLY_FIELD_TYPE } from '@documenso/ui/primitives/document-flow/types';
+import { ElementVisible } from '@documenso/ui/primitives/element-visible';
+import { PopoverHover } from '@documenso/ui/primitives/popover';
+
+export type DocumentReadOnlyFieldsProps = {
+ fields: CompletedField[];
+ documentMeta?: DocumentMeta;
+};
+
+export const DocumentReadOnlyFields = ({ documentMeta, fields }: DocumentReadOnlyFieldsProps) => {
+ const [hiddenFieldIds, setHiddenFieldIds] = useState
>({});
+
+ const handleHideField = (fieldId: string) => {
+ setHiddenFieldIds((prev) => ({ ...prev, [fieldId]: true }));
+ };
+
+ return (
+
+ {fields.map(
+ (field) =>
+ !hiddenFieldIds[field.secondaryId] && (
+
+
+
+
+ {extractInitials(field.Recipient.name || field.Recipient.email)}
+
+
+ }
+ contentProps={{
+ className: 'flex w-fit flex-col py-2.5 text-sm',
+ }}
+ >
+
+
+ {field.Recipient.name
+ ? `${field.Recipient.name} (${field.Recipient.email})`
+ : field.Recipient.email}{' '}
+
+ inserted a {FRIENDLY_FIELD_TYPE[field.type].toLowerCase()}
+
+
+
+
+
+
+
+ {match(field)
+ .with({ type: FieldType.SIGNATURE }, (field) =>
+ field.Signature?.signatureImageAsBase64 ? (
+

+ ) : (
+
+ {field.Signature?.typedSignature}
+
+ ),
+ )
+ .with({ type: P.union(FieldType.NAME, FieldType.TEXT, FieldType.EMAIL) }, () => (
+
{field.customText}
+ ))
+ .with({ type: FieldType.DATE }, () => (
+
+ {convertToLocalSystemFormat(
+ field.customText,
+ documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
+ documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
+ )}
+
+ ))
+ .with({ type: FieldType.FREE_SIGNATURE }, () => null)
+ .exhaustive()}
+
+
+ ),
+ )}
+
+ );
+};
diff --git a/packages/lib/server-only/field/get-completed-fields-for-document.ts b/packages/lib/server-only/field/get-completed-fields-for-document.ts
new file mode 100644
index 000000000..304be95ba
--- /dev/null
+++ b/packages/lib/server-only/field/get-completed-fields-for-document.ts
@@ -0,0 +1,29 @@
+import { prisma } from '@documenso/prisma';
+import { SigningStatus } from '@documenso/prisma/client';
+
+export type GetCompletedFieldsForDocumentOptions = {
+ documentId: number;
+};
+
+export const getCompletedFieldsForDocument = async ({
+ documentId,
+}: GetCompletedFieldsForDocumentOptions) => {
+ return await prisma.field.findMany({
+ where: {
+ documentId,
+ Recipient: {
+ signingStatus: SigningStatus.SIGNED,
+ },
+ inserted: true,
+ },
+ include: {
+ Signature: true,
+ Recipient: {
+ select: {
+ name: true,
+ email: true,
+ },
+ },
+ },
+ });
+};
diff --git a/packages/lib/server-only/field/get-completed-fields-for-token.ts b/packages/lib/server-only/field/get-completed-fields-for-token.ts
new file mode 100644
index 000000000..d84fa1343
--- /dev/null
+++ b/packages/lib/server-only/field/get-completed-fields-for-token.ts
@@ -0,0 +1,33 @@
+import { prisma } from '@documenso/prisma';
+import { SigningStatus } from '@documenso/prisma/client';
+
+export type GetCompletedFieldsForTokenOptions = {
+ token: string;
+};
+
+export const getCompletedFieldsForToken = async ({ token }: GetCompletedFieldsForTokenOptions) => {
+ return await prisma.field.findMany({
+ where: {
+ Document: {
+ Recipient: {
+ some: {
+ token,
+ },
+ },
+ },
+ Recipient: {
+ signingStatus: SigningStatus.SIGNED,
+ },
+ inserted: true,
+ },
+ include: {
+ Signature: true,
+ Recipient: {
+ select: {
+ name: true,
+ email: true,
+ },
+ },
+ },
+ });
+};
diff --git a/packages/lib/server-only/template/create-document-from-template.ts b/packages/lib/server-only/template/create-document-from-template.ts
index 8ae5fecaf..79a3f6f25 100644
--- a/packages/lib/server-only/template/create-document-from-template.ts
+++ b/packages/lib/server-only/template/create-document-from-template.ts
@@ -89,6 +89,10 @@ export const createDocumentFromTemplate = async ({
const documentRecipient = document.Recipient.find((doc) => doc.email === recipient?.email);
+ if (!documentRecipient) {
+ throw new Error('Recipient not found.');
+ }
+
return {
type: field.type,
page: field.page,
@@ -99,7 +103,7 @@ export const createDocumentFromTemplate = async ({
customText: field.customText,
inserted: field.inserted,
documentId: document.id,
- recipientId: documentRecipient?.id || null,
+ recipientId: documentRecipient.id,
};
}),
});
diff --git a/packages/lib/server-only/template/duplicate-template.ts b/packages/lib/server-only/template/duplicate-template.ts
index 97b3f0a0b..963d78bde 100644
--- a/packages/lib/server-only/template/duplicate-template.ts
+++ b/packages/lib/server-only/template/duplicate-template.ts
@@ -81,6 +81,10 @@ export const duplicateTemplate = async ({
(doc) => doc.email === recipient?.email,
);
+ if (!duplicatedTemplateRecipient) {
+ throw new Error('Recipient not found.');
+ }
+
return {
type: field.type,
page: field.page,
@@ -91,7 +95,7 @@ export const duplicateTemplate = async ({
customText: field.customText,
inserted: field.inserted,
templateId: duplicatedTemplate.id,
- recipientId: duplicatedTemplateRecipient?.id || null,
+ recipientId: duplicatedTemplateRecipient.id,
};
}),
});
diff --git a/packages/lib/types/fields.ts b/packages/lib/types/fields.ts
new file mode 100644
index 000000000..1b999310d
--- /dev/null
+++ b/packages/lib/types/fields.ts
@@ -0,0 +1,3 @@
+import type { getCompletedFieldsForToken } from '../server-only/field/get-completed-fields-for-token';
+
+export type CompletedField = Awaited>[number];
diff --git a/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql b/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
new file mode 100644
index 000000000..62845de28
--- /dev/null
+++ b/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
@@ -0,0 +1,8 @@
+/*
+ Warnings:
+
+ - Made the column `recipientId` on table `Field` required. This step will fail if there are existing NULL values in that column.
+
+*/
+-- AlterTable
+ALTER TABLE "Field" ALTER COLUMN "recipientId" SET NOT NULL;
diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma
index 35d429779..c0e68d53f 100644
--- a/packages/prisma/schema.prisma
+++ b/packages/prisma/schema.prisma
@@ -386,7 +386,7 @@ model Field {
secondaryId String @unique @default(cuid())
documentId Int?
templateId Int?
- recipientId Int?
+ recipientId Int
type FieldType
page Int
positionX Decimal @default(0)
@@ -397,7 +397,7 @@ model Field {
inserted Boolean
Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
- Recipient Recipient? @relation(fields: [recipientId], references: [id], onDelete: Cascade)
+ Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
Signature Signature?
@@index([documentId])
diff --git a/packages/ui/components/field/field.tsx b/packages/ui/components/field/field.tsx
index e40b2e3d9..ce62443de 100644
--- a/packages/ui/components/field/field.tsx
+++ b/packages/ui/components/field/field.tsx
@@ -19,6 +19,7 @@ export type FieldContainerPortalProps = {
field: Field;
className?: string;
children: React.ReactNode;
+ cardClassName?: string;
};
export function FieldContainerPortal({
@@ -44,7 +45,7 @@ export function FieldContainerPortal({
);
}
-export function FieldRootContainer({ field, children }: FieldContainerPortalProps) {
+export function FieldRootContainer({ field, children, cardClassName }: FieldContainerPortalProps) {
const [isValidating, setIsValidating] = useState(false);
const ref = React.useRef(null);
@@ -78,6 +79,7 @@ export function FieldRootContainer({ field, children }: FieldContainerPortalProp
{
'border-orange-300 ring-1 ring-orange-300': !field.inserted && isValidating,
},
+ cardClassName,
)}
ref={ref}
data-inserted={field.inserted ? 'true' : 'false'}
diff --git a/packages/ui/primitives/popover.tsx b/packages/ui/primitives/popover.tsx
index e84f6cc6d..62462322b 100644
--- a/packages/ui/primitives/popover.tsx
+++ b/packages/ui/primitives/popover.tsx
@@ -30,4 +30,66 @@ const PopoverContent = React.forwardRef<
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
-export { Popover, PopoverTrigger, PopoverContent };
+type PopoverHoverProps = {
+ trigger: React.ReactNode;
+ children: React.ReactNode;
+ contentProps?: React.ComponentPropsWithoutRef;
+};
+
+const PopoverHover = ({ trigger, children, contentProps }: PopoverHoverProps) => {
+ const [open, setOpen] = React.useState(false);
+
+ const isControlled = React.useRef(false);
+ const isMouseOver = React.useRef(false);
+
+ const onMouseEnter = () => {
+ isMouseOver.current = true;
+
+ if (isControlled.current) {
+ return;
+ }
+
+ setOpen(true);
+ };
+
+ const onMouseLeave = () => {
+ isMouseOver.current = false;
+
+ if (isControlled.current) {
+ return;
+ }
+
+ setTimeout(() => {
+ setOpen(isMouseOver.current);
+ }, 200);
+ };
+
+ const onOpenChange = (newOpen: boolean) => {
+ isControlled.current = newOpen;
+
+ setOpen(newOpen);
+ };
+
+ return (
+
+
+ {trigger}
+
+
+
+ {children}
+
+
+ );
+};
+
+export { Popover, PopoverTrigger, PopoverContent, PopoverHover };
From f6e6dac46c681f6666ec90cd5245482f4030c0a5 Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Fri, 19 Apr 2024 17:58:32 +0700
Subject: [PATCH 04/13] fix: update migration to drop invalid fields
---
.../migration.sql | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql b/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
index 62845de28..ee027d90e 100644
--- a/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
+++ b/packages/prisma/migrations/20240418140819_remove_impossible_field_optional_states/migration.sql
@@ -4,5 +4,8 @@
- Made the column `recipientId` on table `Field` required. This step will fail if there are existing NULL values in that column.
*/
+-- Drop all Fields where the recipientId is null
+DELETE FROM "Field" WHERE "recipientId" IS NULL;
+
-- AlterTable
ALTER TABLE "Field" ALTER COLUMN "recipientId" SET NOT NULL;
From afaeba97393094017dc1c85f544ea4b6bf4cc16d Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Mon, 22 Apr 2024 13:31:49 +0700
Subject: [PATCH 05/13] fix: resize fields
---
.../document/document-read-only-fields.tsx | 25 +++++++++----------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/apps/web/src/components/document/document-read-only-fields.tsx b/apps/web/src/components/document/document-read-only-fields.tsx
index 530066fa8..95a907d8f 100644
--- a/apps/web/src/components/document/document-read-only-fields.tsx
+++ b/apps/web/src/components/document/document-read-only-fields.tsx
@@ -75,7 +75,7 @@ export const DocumentReadOnlyFields = ({ documentMeta, fields }: DocumentReadOnl
-
+
{match(field)
.with({ type: FieldType.SIGNATURE }, (field) =>
field.Signature?.signatureImageAsBase64 ? (
@@ -90,18 +90,17 @@ export const DocumentReadOnlyFields = ({ documentMeta, fields }: DocumentReadOnl
),
)
- .with({ type: P.union(FieldType.NAME, FieldType.TEXT, FieldType.EMAIL) }, () => (
-
{field.customText}
- ))
- .with({ type: FieldType.DATE }, () => (
-
- {convertToLocalSystemFormat(
- field.customText,
- documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
- documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
- )}
-
- ))
+ .with(
+ { type: P.union(FieldType.NAME, FieldType.TEXT, FieldType.EMAIL) },
+ () => field.customText,
+ )
+ .with({ type: FieldType.DATE }, () =>
+ convertToLocalSystemFormat(
+ field.customText,
+ documentMeta?.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT,
+ documentMeta?.timezone ?? DEFAULT_DOCUMENT_TIME_ZONE,
+ ),
+ )
.with({ type: FieldType.FREE_SIGNATURE }, () => null)
.exhaustive()}
From 87423e240af3c915b7ec70eca865f3fc1f3a5fe1 Mon Sep 17 00:00:00 2001
From: Mythie
Date: Wed, 24 Apr 2024 17:32:11 +1000
Subject: [PATCH 06/13] chore: update foreign key constraints
---
.../migration.sql | 23 +++++++++++++++++++
packages/prisma/schema.prisma | 10 ++++----
2 files changed, 28 insertions(+), 5 deletions(-)
create mode 100644 packages/prisma/migrations/20240424072655_update_foreign_key_constraints/migration.sql
diff --git a/packages/prisma/migrations/20240424072655_update_foreign_key_constraints/migration.sql b/packages/prisma/migrations/20240424072655_update_foreign_key_constraints/migration.sql
new file mode 100644
index 000000000..89c38943d
--- /dev/null
+++ b/packages/prisma/migrations/20240424072655_update_foreign_key_constraints/migration.sql
@@ -0,0 +1,23 @@
+-- DropForeignKey
+ALTER TABLE "PasswordResetToken" DROP CONSTRAINT "PasswordResetToken_userId_fkey";
+
+-- DropForeignKey
+ALTER TABLE "Signature" DROP CONSTRAINT "Signature_fieldId_fkey";
+
+-- DropForeignKey
+ALTER TABLE "Team" DROP CONSTRAINT "Team_ownerUserId_fkey";
+
+-- DropForeignKey
+ALTER TABLE "TeamMember" DROP CONSTRAINT "TeamMember_userId_fkey";
+
+-- AddForeignKey
+ALTER TABLE "PasswordResetToken" ADD CONSTRAINT "PasswordResetToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "Signature" ADD CONSTRAINT "Signature_fieldId_fkey" FOREIGN KEY ("fieldId") REFERENCES "Field"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "Team" ADD CONSTRAINT "Team_ownerUserId_fkey" FOREIGN KEY ("ownerUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE "TeamMember" ADD CONSTRAINT "TeamMember_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 8971f837f..97b6e9eeb 100644
--- a/packages/prisma/schema.prisma
+++ b/packages/prisma/schema.prisma
@@ -98,7 +98,7 @@ model PasswordResetToken {
createdAt DateTime @default(now())
expiry DateTime
userId Int
- User User @relation(fields: [userId], references: [id])
+ User User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model Passkey {
@@ -415,7 +415,7 @@ model Signature {
typedSignature String?
Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
- Field Field @relation(fields: [fieldId], references: [id], onDelete: Restrict)
+ Field Field @relation(fields: [fieldId], references: [id], onDelete: Cascade)
@@index([recipientId])
}
@@ -457,7 +457,7 @@ model Team {
emailVerification TeamEmailVerification?
transferVerification TeamTransferVerification?
- owner User @relation(fields: [ownerUserId], references: [id])
+ owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
subscription Subscription?
document Document[]
@@ -483,7 +483,7 @@ model TeamMember {
createdAt DateTime @default(now())
role TeamMemberRole
userId Int
- user User @relation(fields: [userId], references: [id])
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
team Team @relation(fields: [teamId], references: [id], onDelete: Cascade)
@@unique([userId, teamId])
@@ -564,5 +564,5 @@ model SiteSettings {
data Json
lastModifiedByUserId Int?
lastModifiedAt DateTime @default(now())
- lastModifiedByUser User? @relation(fields: [lastModifiedByUserId], references: [id])
+ lastModifiedByUser User? @relation(fields: [lastModifiedByUserId], references: [id], onDelete: SetNull)
}
From 713cd09a063d1d97db6e753fb0b2edef29b5357f Mon Sep 17 00:00:00 2001
From: Mythie
Date: Wed, 24 Apr 2024 19:07:18 +1000
Subject: [PATCH 07/13] fix: downgrade playwright
---
package-lock.json | 74 +++++++++++++++++++++++----------------
package.json | 2 +-
packages/lib/package.json | 4 +--
3 files changed, 46 insertions(+), 34 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index fb03b3a67..83d9523c5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"eslint-config-custom": "*",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
- "playwright": "^1.43.0",
+ "playwright": "1.41.0",
"prettier": "^2.5.1",
"rimraf": "^5.0.1",
"turbo": "^1.9.3"
@@ -4702,19 +4702,6 @@
"node": ">=14"
}
},
- "node_modules/@playwright/browser-chromium": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.43.0.tgz",
- "integrity": "sha512-F0S4KIqSqQqm9EgsdtWjaJRpgP8cD2vWZHPSB41YI00PtXUobiv/3AnYISeL7wNuTanND7giaXQ4SIjkcIq3KQ==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "playwright-core": "1.43.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
"node_modules/@playwright/test": {
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz",
@@ -17673,11 +17660,11 @@
}
},
"node_modules/playwright": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz",
- "integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==",
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.0.tgz",
+ "integrity": "sha512-XOsfl5ZtAik/T9oek4V0jAypNlaCNzuKOwVhqhgYT3os6kH34PzbRb74F0VWcLYa5WFdnmxl7qyAHBXvPv7lqQ==",
"dependencies": {
- "playwright-core": "1.43.0"
+ "playwright-core": "1.41.0"
},
"bin": {
"playwright": "cli.js"
@@ -17689,17 +17676,6 @@
"fsevents": "2.3.2"
}
},
- "node_modules/playwright-core": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
- "integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==",
- "bin": {
- "playwright-core": "cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
"node_modules/playwright/node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
@@ -17713,6 +17689,17 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/playwright/node_modules/playwright-core": {
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.0.tgz",
+ "integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@@ -24981,7 +24968,7 @@
"next-auth": "4.24.5",
"oslo": "^0.17.0",
"pdf-lib": "^1.17.1",
- "playwright": "^1.43.0",
+ "playwright": "1.41.0",
"react": "18.2.0",
"remeda": "^1.27.1",
"stripe": "^12.7.0",
@@ -24989,10 +24976,23 @@
"zod": "^3.22.4"
},
"devDependencies": {
- "@playwright/browser-chromium": "^1.43.0",
+ "@playwright/browser-chromium": "1.41.0",
"@types/luxon": "^3.3.1"
}
},
+ "packages/lib/node_modules/@playwright/browser-chromium": {
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.41.0.tgz",
+ "integrity": "sha512-TaHfh3rDsz4+tVKdMMo4kdFOk8/4U6cPyMXHhoiJVmhOhjHXjR0qPMoa5gz5jDGl478cn5SoXmtgKPgTDFuS0g==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "playwright-core": "1.41.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"packages/lib/node_modules/nanoid": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz",
@@ -25010,6 +25010,18 @@
"node": "^14 || ^16 || >=18"
}
},
+ "packages/lib/node_modules/playwright-core": {
+ "version": "1.41.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.0.tgz",
+ "integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
+ "dev": true,
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"packages/prettier-config": {
"name": "@documenso/prettier-config",
"version": "0.0.0",
diff --git a/package.json b/package.json
index 396b2ecfd..70ed541e1 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"eslint-config-custom": "*",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
- "playwright": "^1.43.0",
+ "playwright": "1.41.0",
"prettier": "^2.5.1",
"rimraf": "^5.0.1",
"turbo": "^1.9.3"
diff --git a/packages/lib/package.json b/packages/lib/package.json
index 1aa7e431e..5e40e047b 100644
--- a/packages/lib/package.json
+++ b/packages/lib/package.json
@@ -39,7 +39,7 @@
"next-auth": "4.24.5",
"oslo": "^0.17.0",
"pdf-lib": "^1.17.1",
- "playwright": "^1.43.0",
+ "playwright": "1.41.0",
"react": "18.2.0",
"remeda": "^1.27.1",
"stripe": "^12.7.0",
@@ -48,6 +48,6 @@
},
"devDependencies": {
"@types/luxon": "^3.3.1",
- "@playwright/browser-chromium": "^1.43.0"
+ "@playwright/browser-chromium": "1.41.0"
}
}
\ No newline at end of file
From 41ed6c9ad7f34c9ea430808a8e4f5cf95d9e7037 Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Wed, 24 Apr 2024 19:49:10 +0700
Subject: [PATCH 08/13] fix: disable cert download when document not complete
---
.../documents/[id]/logs/document-logs-page-view.tsx | 6 +++++-
.../documents/[id]/logs/download-certificate-button.tsx | 4 ++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/logs/document-logs-page-view.tsx b/apps/web/src/app/(dashboard)/documents/[id]/logs/document-logs-page-view.tsx
index 2d786b9c9..0556fcd2d 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/logs/document-logs-page-view.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/logs/document-logs-page-view.tsx
@@ -133,7 +133,11 @@ export const DocumentLogsPageView = async ({ params, team }: DocumentLogsPageVie
-
+
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx
index 49a330b94..1f2028358 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx
@@ -2,6 +2,7 @@
import { DownloadIcon } from 'lucide-react';
+import { DocumentStatus } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { cn } from '@documenso/ui/lib/utils';
import { Button } from '@documenso/ui/primitives/button';
@@ -10,11 +11,13 @@ import { useToast } from '@documenso/ui/primitives/use-toast';
export type DownloadCertificateButtonProps = {
className?: string;
documentId: number;
+ documentStatus: DocumentStatus;
};
export const DownloadCertificateButton = ({
className,
documentId,
+ documentStatus,
}: DownloadCertificateButtonProps) => {
const { toast } = useToast();
@@ -69,6 +72,7 @@ export const DownloadCertificateButton = ({
className={cn('w-full sm:w-auto', className)}
loading={isLoading}
variant="outline"
+ disabled={documentStatus !== DocumentStatus.COMPLETED}
onClick={() => void onDownloadCertificatesClick()}
>
{!isLoading && }
From e4cf9c82518a6f38ca1626c8899c89abe92efa46 Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Wed, 24 Apr 2024 19:51:18 +0700
Subject: [PATCH 09/13] fix: add server logic
---
packages/trpc/server/document-router/router.ts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/packages/trpc/server/document-router/router.ts b/packages/trpc/server/document-router/router.ts
index d12002674..64f3c2480 100644
--- a/packages/trpc/server/document-router/router.ts
+++ b/packages/trpc/server/document-router/router.ts
@@ -4,6 +4,7 @@ import { DateTime } from 'luxon';
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
+import { AppError } from '@documenso/lib/errors/app-error';
import { encryptSecondaryData } from '@documenso/lib/server-only/crypto/encrypt';
import { upsertDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
import { createDocument } from '@documenso/lib/server-only/document/create-document';
@@ -20,6 +21,7 @@ import { updateDocumentSettings } from '@documenso/lib/server-only/document/upda
import { updateTitle } from '@documenso/lib/server-only/document/update-title';
import { symmetricEncrypt } from '@documenso/lib/universal/crypto';
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
+import { DocumentStatus } from '@documenso/prisma/client';
import { authenticatedProcedure, procedure, router } from '../trpc';
import {
@@ -413,6 +415,10 @@ export const documentRouter = router({
teamId,
});
+ if (document.status !== DocumentStatus.COMPLETED) {
+ throw new AppError('DOCUMENT_NOT_COMPLETE');
+ }
+
const encrypted = encryptSecondaryData({
data: document.id.toString(),
expiresAt: DateTime.now().plus({ minutes: 5 }).toJSDate().valueOf(),
From 4de122f814b4cbb50ddb9b838f42c5d198102489 Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Wed, 24 Apr 2024 20:07:38 +0700
Subject: [PATCH 10/13] fix: hide account action reauth
---
.../primitives/document-flow/add-settings.tsx | 22 ++++++++++++-------
.../primitives/document-flow/add-signers.tsx | 16 ++++++++------
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/packages/ui/primitives/document-flow/add-settings.tsx b/packages/ui/primitives/document-flow/add-settings.tsx
index ea962dee5..ce52e03c2 100644
--- a/packages/ui/primitives/document-flow/add-settings.tsx
+++ b/packages/ui/primitives/document-flow/add-settings.tsx
@@ -9,7 +9,11 @@ import { useForm } from 'react-hook-form';
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
import { DOCUMENT_AUTH_TYPES } from '@documenso/lib/constants/document-auth';
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
-import { DocumentAccessAuth, DocumentActionAuth } from '@documenso/lib/types/document-auth';
+import {
+ DocumentAccessAuth,
+ DocumentActionAuth,
+ DocumentAuth,
+} from '@documenso/lib/types/document-auth';
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
import { DocumentStatus, type Field, type Recipient, SendStatus } from '@documenso/prisma/client';
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
@@ -216,9 +220,9 @@ export const AddSettingsFormPartial = ({
- -
+ {/*
-
Require account - The recipient must be signed in
-
+ */}
-
Require passkey - The recipient must have an account
and passkey configured via their settings
@@ -242,11 +246,13 @@ export const AddSettingsFormPartial = ({
- {Object.values(DocumentActionAuth).map((authType) => (
-
- {DOCUMENT_AUTH_TYPES[authType].value}
-
- ))}
+ {Object.values(DocumentActionAuth)
+ .filter((auth) => auth !== DocumentAuth.ACCOUNT)
+ .map((authType) => (
+
+ {DOCUMENT_AUTH_TYPES[authType].value}
+
+ ))}
{/* Note: -1 is remapped in the Zod schema to the required value. */}
None
diff --git a/packages/ui/primitives/document-flow/add-signers.tsx b/packages/ui/primitives/document-flow/add-signers.tsx
index b796f4328..2f9f2f234 100644
--- a/packages/ui/primitives/document-flow/add-signers.tsx
+++ b/packages/ui/primitives/document-flow/add-signers.tsx
@@ -302,10 +302,10 @@ export const AddSignersFormPartial = ({
global action signing authentication method configured in
the "General Settings" step
- -
+ {/*
-
Require account - The recipient must be
signed in
-
+ */}
-
Require passkey - The recipient must have
an account and passkey configured via their settings
@@ -326,11 +326,13 @@ export const AddSignersFormPartial = ({
{/* Note: -1 is remapped in the Zod schema to the required value. */}
Inherit authentication method
- {Object.values(RecipientActionAuth).map((authType) => (
-
- {DOCUMENT_AUTH_TYPES[authType].value}
-
- ))}
+ {Object.values(RecipientActionAuth)
+ .filter((auth) => auth !== RecipientActionAuth.ACCOUNT)
+ .map((authType) => (
+
+ {DOCUMENT_AUTH_TYPES[authType].value}
+
+ ))}
From e1573465f6e66b67b47bb83bcb4e5fa0899a3711 Mon Sep 17 00:00:00 2001
From: David Nguyen
Date: Thu, 25 Apr 2024 23:32:59 +0700
Subject: [PATCH 11/13] fix: hide team webhooks from users
---
packages/lib/server-only/webhooks/get-webhooks-by-user-id.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/lib/server-only/webhooks/get-webhooks-by-user-id.ts b/packages/lib/server-only/webhooks/get-webhooks-by-user-id.ts
index 121fc670d..0877d878f 100644
--- a/packages/lib/server-only/webhooks/get-webhooks-by-user-id.ts
+++ b/packages/lib/server-only/webhooks/get-webhooks-by-user-id.ts
@@ -4,6 +4,7 @@ export const getWebhooksByUserId = async (userId: number) => {
return await prisma.webhook.findMany({
where: {
userId,
+ teamId: null,
},
orderBy: {
createdAt: 'desc',
From 88dedc98298a29d9c0438d9491ab45f3fc38e315 Mon Sep 17 00:00:00 2001
From: Mythie
Date: Fri, 26 Apr 2024 13:18:31 +1000
Subject: [PATCH 12/13] fix: use cdp and upgrade playwright again
---
package-lock.json | 26 +++++++++----------
package.json | 2 +-
packages/lib/package.json | 4 +--
.../htmltopdf/get-certificate-pdf.ts | 4 ++-
4 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 83d9523c5..e9e822cf2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"eslint-config-custom": "*",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
- "playwright": "1.41.0",
+ "playwright": "1.43.0",
"prettier": "^2.5.1",
"rimraf": "^5.0.1",
"turbo": "^1.9.3"
@@ -17660,11 +17660,11 @@
}
},
"node_modules/playwright": {
- "version": "1.41.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.0.tgz",
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz",
"integrity": "sha512-XOsfl5ZtAik/T9oek4V0jAypNlaCNzuKOwVhqhgYT3os6kH34PzbRb74F0VWcLYa5WFdnmxl7qyAHBXvPv7lqQ==",
"dependencies": {
- "playwright-core": "1.41.0"
+ "playwright-core": "1.43.0"
},
"bin": {
"playwright": "cli.js"
@@ -17690,8 +17690,8 @@
}
},
"node_modules/playwright/node_modules/playwright-core": {
- "version": "1.41.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.0.tgz",
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
"integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
"bin": {
"playwright-core": "cli.js"
@@ -24968,7 +24968,7 @@
"next-auth": "4.24.5",
"oslo": "^0.17.0",
"pdf-lib": "^1.17.1",
- "playwright": "1.41.0",
+ "playwright": "1.43.0",
"react": "18.2.0",
"remeda": "^1.27.1",
"stripe": "^12.7.0",
@@ -24976,18 +24976,18 @@
"zod": "^3.22.4"
},
"devDependencies": {
- "@playwright/browser-chromium": "1.41.0",
+ "@playwright/browser-chromium": "1.43.0",
"@types/luxon": "^3.3.1"
}
},
"packages/lib/node_modules/@playwright/browser-chromium": {
- "version": "1.41.0",
- "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.41.0.tgz",
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.43.0.tgz",
"integrity": "sha512-TaHfh3rDsz4+tVKdMMo4kdFOk8/4U6cPyMXHhoiJVmhOhjHXjR0qPMoa5gz5jDGl478cn5SoXmtgKPgTDFuS0g==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
- "playwright-core": "1.41.0"
+ "playwright-core": "1.43.0"
},
"engines": {
"node": ">=16"
@@ -25011,8 +25011,8 @@
}
},
"packages/lib/node_modules/playwright-core": {
- "version": "1.41.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.0.tgz",
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
"integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
"dev": true,
"bin": {
diff --git a/package.json b/package.json
index 70ed541e1..3480aae28 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,7 @@
"eslint-config-custom": "*",
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
- "playwright": "1.41.0",
+ "playwright": "1.43.0",
"prettier": "^2.5.1",
"rimraf": "^5.0.1",
"turbo": "^1.9.3"
diff --git a/packages/lib/package.json b/packages/lib/package.json
index 5e40e047b..c6144df92 100644
--- a/packages/lib/package.json
+++ b/packages/lib/package.json
@@ -39,7 +39,7 @@
"next-auth": "4.24.5",
"oslo": "^0.17.0",
"pdf-lib": "^1.17.1",
- "playwright": "1.41.0",
+ "playwright": "1.43.0",
"react": "18.2.0",
"remeda": "^1.27.1",
"stripe": "^12.7.0",
@@ -48,6 +48,6 @@
},
"devDependencies": {
"@types/luxon": "^3.3.1",
- "@playwright/browser-chromium": "1.41.0"
+ "@playwright/browser-chromium": "1.43.0"
}
}
\ No newline at end of file
diff --git a/packages/lib/server-only/htmltopdf/get-certificate-pdf.ts b/packages/lib/server-only/htmltopdf/get-certificate-pdf.ts
index a7182410e..dee40d41a 100644
--- a/packages/lib/server-only/htmltopdf/get-certificate-pdf.ts
+++ b/packages/lib/server-only/htmltopdf/get-certificate-pdf.ts
@@ -18,7 +18,9 @@ export const getCertificatePdf = async ({ documentId }: GetCertificatePdfOptions
let browser: Browser;
if (process.env.NEXT_PRIVATE_BROWSERLESS_URL) {
- browser = await chromium.connect(process.env.NEXT_PRIVATE_BROWSERLESS_URL);
+ // !: Use CDP rather than the default `connect` method to avoid coupling to the playwright version.
+ // !: Previously we would have to keep the playwright version in sync with the browserless version to avoid errors.
+ browser = await chromium.connectOverCDP(process.env.NEXT_PRIVATE_BROWSERLESS_URL);
} else {
browser = await chromium.launch();
}
From 481d739c37e7ba147b9c3120a1bac47ea0f7919c Mon Sep 17 00:00:00 2001
From: Mythie
Date: Fri, 26 Apr 2024 13:25:16 +1000
Subject: [PATCH 13/13] chore: update package-lock
---
package-lock.json | 84 ++++++++++++++++++++---------------------------
1 file changed, 36 insertions(+), 48 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index e9e822cf2..479463b25 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4702,13 +4702,26 @@
"node": ">=14"
}
},
+ "node_modules/@playwright/browser-chromium": {
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.43.0.tgz",
+ "integrity": "sha512-F0S4KIqSqQqm9EgsdtWjaJRpgP8cD2vWZHPSB41YI00PtXUobiv/3AnYISeL7wNuTanND7giaXQ4SIjkcIq3KQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "playwright-core": "1.43.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/@playwright/test": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz",
- "integrity": "sha512-PdW+kn4eV99iP5gxWNSDQCbhMaDVej+RXL5xr6t04nbKLCBwYtA046t7ofoczHOm8u6c+45hpDKQVZqtqwkeQg==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz",
+ "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==",
"dev": true,
"dependencies": {
- "playwright": "1.40.0"
+ "playwright": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -4732,12 +4745,12 @@
}
},
"node_modules/@playwright/test/node_modules/playwright": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz",
- "integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
+ "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
"dev": true,
"dependencies": {
- "playwright-core": "1.40.0"
+ "playwright-core": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -4750,9 +4763,9 @@
}
},
"node_modules/@playwright/test/node_modules/playwright-core": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz",
- "integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
+ "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -17662,7 +17675,7 @@
"node_modules/playwright": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.0.tgz",
- "integrity": "sha512-XOsfl5ZtAik/T9oek4V0jAypNlaCNzuKOwVhqhgYT3os6kH34PzbRb74F0VWcLYa5WFdnmxl7qyAHBXvPv7lqQ==",
+ "integrity": "sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==",
"dependencies": {
"playwright-core": "1.43.0"
},
@@ -17676,6 +17689,17 @@
"fsevents": "2.3.2"
}
},
+ "node_modules/playwright-core": {
+ "version": "1.43.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
+ "integrity": "sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/playwright/node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
@@ -17689,17 +17713,6 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
- "node_modules/playwright/node_modules/playwright-core": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
- "integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
- "bin": {
- "playwright-core": "cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@@ -24980,19 +24993,6 @@
"@types/luxon": "^3.3.1"
}
},
- "packages/lib/node_modules/@playwright/browser-chromium": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.43.0.tgz",
- "integrity": "sha512-TaHfh3rDsz4+tVKdMMo4kdFOk8/4U6cPyMXHhoiJVmhOhjHXjR0qPMoa5gz5jDGl478cn5SoXmtgKPgTDFuS0g==",
- "dev": true,
- "hasInstallScript": true,
- "dependencies": {
- "playwright-core": "1.43.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
"packages/lib/node_modules/nanoid": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz",
@@ -25010,18 +25010,6 @@
"node": "^14 || ^16 || >=18"
}
},
- "packages/lib/node_modules/playwright-core": {
- "version": "1.43.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.0.tgz",
- "integrity": "sha512-UGKASUhXmvqm2Lxa1fNr8sFwAtqjpgBRr9jQ7XBI8Rn5uFiEowGUGwrruUQsVPIom4bk7Lt+oLGpXobnXzrBIw==",
- "dev": true,
- "bin": {
- "playwright-core": "cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
"packages/prettier-config": {
"name": "@documenso/prettier-config",
"version": "0.0.0",