feat: add envelope editor

This commit is contained in:
David Nguyen
2025-10-12 23:35:54 +11:00
parent bf89bc781b
commit 0da8e7dbc6
307 changed files with 24657 additions and 3681 deletions

View File

@ -8,6 +8,8 @@ import { createDocumentData } from '@documenso/lib/server-only/document-data/cre
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
import { createEnvelope } from '@documenso/lib/server-only/envelope/create-envelope';
import { duplicateEnvelope } from '@documenso/lib/server-only/envelope/duplicate-envelope';
import { updateEnvelope } from '@documenso/lib/server-only/envelope/update-envelope';
import {
ZCreateDocumentFromDirectTemplateResponseSchema,
createDocumentFromDirectTemplate,
@ -16,11 +18,9 @@ import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/
import { createTemplateDirectLink } from '@documenso/lib/server-only/template/create-template-direct-link';
import { deleteTemplate } from '@documenso/lib/server-only/template/delete-template';
import { deleteTemplateDirectLink } from '@documenso/lib/server-only/template/delete-template-direct-link';
import { duplicateTemplate } from '@documenso/lib/server-only/template/duplicate-template';
import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link';
import { updateTemplate } from '@documenso/lib/server-only/template/update-template';
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope';
import { mapEnvelopeToTemplateLite } from '@documenso/lib/utils/templates';
@ -91,6 +91,7 @@ export const templateRouter = router({
return {
id: legacyTemplateId,
envelopeId: envelope.id,
type: envelope.templateType,
visibility: envelope.visibility,
externalId: envelope.externalId,
@ -139,7 +140,10 @@ export const templateRouter = router({
});
return await getTemplateById({
id: templateId,
id: {
type: 'templateId',
id: templateId,
},
userId: ctx.user.id,
teamId,
});
@ -175,6 +179,7 @@ export const templateRouter = router({
const envelope = await createEnvelope({
userId: ctx.user.id,
teamId,
internalVersion: 1,
data: {
type: EnvelopeType.TEMPLATE,
title,
@ -240,6 +245,7 @@ export const templateRouter = router({
const createdTemplate = await createEnvelope({
userId: user.id,
teamId,
internalVersion: 1,
data: {
type: EnvelopeType.TEMPLATE,
title,
@ -264,7 +270,10 @@ export const templateRouter = router({
const legacyTemplateId = mapSecondaryIdToTemplateId(createdTemplate.secondaryId);
const fullTemplate = await getTemplateById({
id: legacyTemplateId,
id: {
type: 'templateId',
id: legacyTemplateId,
},
userId: user.id,
teamId,
});
@ -300,12 +309,19 @@ export const templateRouter = router({
},
});
const envelope = await updateTemplate({
const envelope = await updateEnvelope({
userId,
teamId,
templateId,
data,
id: {
type: 'templateId',
id: templateId,
},
data: {
...data,
templateType: data?.type, // Backwards compatibility.
},
meta,
requestMetadata: ctx.metadata,
});
return mapEnvelopeToTemplateLite(envelope);
@ -335,7 +351,7 @@ export const templateRouter = router({
},
});
const envelope = await duplicateTemplate({
const duplicatedEnvelope = await duplicateEnvelope({
userId: ctx.user.id,
teamId,
id: {
@ -344,7 +360,7 @@ export const templateRouter = router({
},
});
return mapEnvelopeToTemplateLite(envelope);
return mapEnvelopeToTemplateLite(duplicatedEnvelope.envelope);
}),
/**
@ -372,7 +388,14 @@ export const templateRouter = router({
},
});
await deleteTemplate({ userId, id: templateId, teamId });
await deleteTemplate({
userId,
id: {
type: 'templateId',
id: templateId,
},
teamId,
});
return ZGenericSuccessResponse;
}),
@ -415,6 +438,16 @@ export const templateRouter = router({
throw new Error('You have reached your document limit.');
}
// Backwards compatibility mapping since we need the envelopeItemId for the custom document data.
const customDocumentData = customDocumentDataId
? [
{
documentDataId: customDocumentDataId,
envelopeItemId: undefined,
},
]
: input.customDocumentData || [];
const envelope: Envelope = await createDocumentFromTemplate({
id: {
type: 'templateId',
@ -423,7 +456,7 @@ export const templateRouter = router({
teamId,
userId: ctx.user.id,
recipients,
customDocumentDataId,
customDocumentData,
requestMetadata: ctx.metadata,
folderId,
prefillFields,
@ -534,7 +567,14 @@ export const templateRouter = router({
},
});
const template = await getTemplateById({ id: templateId, teamId, userId: ctx.user.id });
const template = await getTemplateById({
id: {
type: 'templateId',
id: templateId,
},
teamId,
userId: ctx.user.id,
});
const limits = await getServerLimits({ userId: ctx.user.id, teamId: template.teamId });
@ -641,7 +681,10 @@ export const templateRouter = router({
}
const template = await getTemplateById({
id: templateId,
id: {
type: 'templateId',
id: templateId,
},
teamId,
userId: user.id,
});

View File

@ -7,15 +7,6 @@ import {
ZDocumentActionAuthTypesSchema,
} from '@documenso/lib/types/document-auth';
import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';
import { ZFieldMetaPrefillFieldsSchema } from '@documenso/lib/types/field-meta';
import { ZFindResultResponse, ZFindSearchParamsSchema } from '@documenso/lib/types/search-params';
import {
ZTemplateLiteSchema,
ZTemplateManySchema,
ZTemplateSchema,
} from '@documenso/lib/types/template';
import { TemplateDirectLinkSchema } from '@documenso/prisma/generated/zod/modelSchema/TemplateDirectLinkSchema';
import {
ZDocumentMetaDateFormatSchema,
ZDocumentMetaDistributionMethodSchema,
@ -27,7 +18,16 @@ import {
ZDocumentMetaTimezoneSchema,
ZDocumentMetaTypedSignatureEnabledSchema,
ZDocumentMetaUploadSignatureEnabledSchema,
} from '../document-router/schema';
} from '@documenso/lib/types/document-meta';
import { ZFieldMetaPrefillFieldsSchema } from '@documenso/lib/types/field-meta';
import { ZFindResultResponse, ZFindSearchParamsSchema } from '@documenso/lib/types/search-params';
import {
ZTemplateLiteSchema,
ZTemplateManySchema,
ZTemplateSchema,
} from '@documenso/lib/types/template';
import { TemplateDirectLinkSchema } from '@documenso/prisma/generated/zod/modelSchema/TemplateDirectLinkSchema';
import { ZSignFieldWithTokenMutationSchema } from '../field-router/schema';
export const MAX_TEMPLATE_PUBLIC_TITLE_LENGTH = 50;
@ -109,9 +109,21 @@ export const ZCreateDocumentFromTemplateRequestSchema = z.object({
customDocumentDataId: z
.string()
.describe(
'The data ID of an alternative PDF to use when creating the document. If not provided, the PDF attached to the template will be used.',
'[DEPRECATED] - Use customDocumentData instead. The data ID of an alternative PDF to use when creating the document. If not provided, the PDF attached to the template will be used.',
)
.optional(),
customDocumentData: z
.array(
z.object({
documentDataId: z.string(),
envelopeItemId: z.string(),
}),
)
.describe(
'The data IDs of alternative PDFs to use when creating the document. If not provided, the PDF attached to the template will be used.',
)
.optional(),
folderId: z
.string()
.describe(
@ -150,7 +162,7 @@ const GenericDirectLinkResponseSchema = TemplateDirectLinkSchema.pick({
createdAt: true,
enabled: true,
directTemplateRecipientId: true,
// envelopeId: true, // Todo: Envelopes
envelopeId: true,
}).extend({
templateId: z.number(),
});