mirror of
https://github.com/documenso/documenso.git
synced 2026-07-25 01:15:49 +10:00
chore: merge main, resolve biome formatting conflicts
Merge origin/main into feat/bulk-download. Take PR's bulk action bar design (escape-key dismiss, popover pill with count badge, optional download button via onDownloadClick) and the documents page bulk download state (envelopeMetaCache cached across pages, selected envelopes mapped from cache for download). Imports reordered into biome's @documenso → external → relative groups; combined the @prisma/client import line to include DocumentStatus as PrismaDocumentStatus alongside EnvelopeType, FolderType, OrganisationType.
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import type { Team, User } from '@prisma/client';
|
||||
import { nanoid } from 'nanoid';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { createEnvelope } from '@documenso/lib/server-only/envelope/create-envelope';
|
||||
import { incrementDocumentId } from '@documenso/lib/server-only/envelope/increment-id';
|
||||
import {
|
||||
@@ -19,6 +15,9 @@ import {
|
||||
FIELD_TEXT_META_DEFAULT_VALUES,
|
||||
} from '@documenso/lib/types/field-meta';
|
||||
import { prefixedId } from '@documenso/lib/universal/id';
|
||||
import type { Team, User } from '@prisma/client';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { prisma } from '..';
|
||||
import {
|
||||
@@ -35,9 +34,7 @@ import {
|
||||
import { seedTeam } from './teams';
|
||||
import { seedUser } from './users';
|
||||
|
||||
const examplePdf = fs
|
||||
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
|
||||
.toString('base64');
|
||||
const examplePdf = fs.readFileSync(path.join(__dirname, '../../../assets/example.pdf')).toString('base64');
|
||||
|
||||
type DocumentToSeed = {
|
||||
sender: User;
|
||||
@@ -74,11 +71,7 @@ export const seedDocuments = async (documents: DocumentToSeed[]) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const seedBlankDocument = async (
|
||||
owner: User,
|
||||
teamId: number,
|
||||
options: CreateDocumentOptions = {},
|
||||
) => {
|
||||
export const seedBlankDocument = async (owner: User, teamId: number, options: CreateDocumentOptions = {}) => {
|
||||
const { key, createDocumentOptions = {}, internalVersion = 1 } = options;
|
||||
|
||||
const documentData = await prisma.documentData.create({
|
||||
@@ -316,9 +309,7 @@ export const seedDraftDocument = async (
|
||||
const documentId = await incrementDocumentId();
|
||||
|
||||
const envelopeTitle =
|
||||
typeof createDocumentOptions.title === 'string'
|
||||
? createDocumentOptions.title
|
||||
: `[TEST] Document ${key} - Draft`;
|
||||
typeof createDocumentOptions.title === 'string' ? createDocumentOptions.title : `[TEST] Document ${key} - Draft`;
|
||||
|
||||
const document = await prisma.envelope.create({
|
||||
data: {
|
||||
|
||||
@@ -9,11 +9,7 @@ type CreateFolderOptions = {
|
||||
createFolderOptions?: Partial<Prisma.FolderUncheckedCreateInput>;
|
||||
};
|
||||
|
||||
export const seedBlankFolder = async (
|
||||
user: User,
|
||||
teamId: number,
|
||||
options: CreateFolderOptions = {},
|
||||
) => {
|
||||
export const seedBlankFolder = async (user: User, teamId: number, options: CreateFolderOptions = {}) => {
|
||||
return await prisma.folder.create({
|
||||
data: {
|
||||
name: 'My folder',
|
||||
|
||||
@@ -3,18 +3,12 @@ import path from 'node:path';
|
||||
|
||||
import { ALIGNMENT_TEST_FIELDS } from '@documenso/app-tests/constants/field-alignment-pdf';
|
||||
import { FIELD_META_TEST_FIELDS } from '@documenso/app-tests/constants/field-meta-pdf';
|
||||
import { OVERFLOW_TEST_FIELDS } from '@documenso/app-tests/constants/field-overflow-pdf';
|
||||
import { isBase64Image } from '@documenso/lib/constants/signatures';
|
||||
import {
|
||||
incrementDocumentId,
|
||||
incrementTemplateId,
|
||||
} from '@documenso/lib/server-only/envelope/increment-id';
|
||||
import { incrementDocumentId, incrementTemplateId } from '@documenso/lib/server-only/envelope/increment-id';
|
||||
import { nanoid, prefixedId } from '@documenso/lib/universal/id';
|
||||
|
||||
import { DIRECT_TEMPLATE_RECIPIENT_EMAIL, DIRECT_TEMPLATE_RECIPIENT_NAME } from '../../lib/constants/direct-templates';
|
||||
import { prisma } from '..';
|
||||
import {
|
||||
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
DIRECT_TEMPLATE_RECIPIENT_NAME,
|
||||
} from '../../lib/constants/direct-templates';
|
||||
import {
|
||||
DocumentDataType,
|
||||
DocumentSource,
|
||||
@@ -39,9 +33,7 @@ const createDocumentData = async ({ documentData }: { documentData: string }) =>
|
||||
};
|
||||
|
||||
export const seedDatabase = async () => {
|
||||
const examplePdf = fs
|
||||
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
|
||||
.toString('base64');
|
||||
const examplePdf = fs.readFileSync(path.join(__dirname, '../../../assets/example.pdf')).toString('base64');
|
||||
|
||||
const exampleUserExists = await prisma.user.findFirst({
|
||||
where: {
|
||||
@@ -183,6 +175,22 @@ export const seedDatabase = async () => {
|
||||
userId: adminUser.user.id,
|
||||
teamId: adminUser.team.id,
|
||||
}),
|
||||
seedOverflowTestDocument({
|
||||
userId: exampleUser.user.id,
|
||||
teamId: exampleUser.team.id,
|
||||
recipientName: exampleUser.user.name || '',
|
||||
recipientEmail: exampleUser.user.email,
|
||||
insertFields: false,
|
||||
status: DocumentStatus.DRAFT,
|
||||
}),
|
||||
seedOverflowTestDocument({
|
||||
userId: adminUser.user.id,
|
||||
teamId: adminUser.team.id,
|
||||
recipientName: adminUser.user.name || '',
|
||||
recipientEmail: adminUser.user.email,
|
||||
insertFields: false,
|
||||
status: DocumentStatus.DRAFT,
|
||||
}),
|
||||
seedAlignmentTestDocument({
|
||||
userId: exampleUser.user.id,
|
||||
teamId: exampleUser.team.id,
|
||||
@@ -285,9 +293,7 @@ export const seedAlignmentTestDocument = async ({
|
||||
.readFileSync(path.join(__dirname, '../../../assets/field-font-alignment.pdf'))
|
||||
.toString('base64');
|
||||
|
||||
const fieldMetaPdf = fs
|
||||
.readFileSync(path.join(__dirname, '../../../assets/field-meta.pdf'))
|
||||
.toString('base64');
|
||||
const fieldMetaPdf = fs.readFileSync(path.join(__dirname, '../../../assets/field-meta.pdf')).toString('base64');
|
||||
|
||||
const alignmentDocumentData = await createDocumentData({ documentData: alignmentPdf });
|
||||
const fieldMetaDocumentData = await createDocumentData({ documentData: fieldMetaPdf });
|
||||
@@ -351,9 +357,7 @@ export const seedAlignmentTestDocument = async ({
|
||||
const { id, recipients, envelopeItems } = createdEnvelope;
|
||||
|
||||
if (isDirectTemplate) {
|
||||
const directTemplateRecpient = recipients.find(
|
||||
(recipient) => recipient.email === DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
);
|
||||
const directTemplateRecpient = recipients.find((recipient) => recipient.email === DIRECT_TEMPLATE_RECIPIENT_EMAIL);
|
||||
|
||||
if (!directTemplateRecpient) {
|
||||
throw new Error('Need to create a direct template recipient');
|
||||
@@ -387,9 +391,7 @@ export const seedAlignmentTestDocument = async ({
|
||||
envelopeId: id,
|
||||
customText: insertFields ? field.customText : '',
|
||||
inserted:
|
||||
insertFields &&
|
||||
((!field?.fieldMeta?.readOnly && Boolean(field.customText)) ||
|
||||
field.type === 'SIGNATURE'),
|
||||
insertFields && ((!field?.fieldMeta?.readOnly && Boolean(field.customText)) || field.type === 'SIGNATURE'),
|
||||
signature:
|
||||
field.signature && insertFields
|
||||
? {
|
||||
@@ -415,9 +417,124 @@ export const seedAlignmentTestDocument = async ({
|
||||
envelopeId: id,
|
||||
customText: insertFields ? field.customText : '',
|
||||
inserted:
|
||||
insertFields &&
|
||||
((!field?.fieldMeta?.readOnly && Boolean(field.customText)) ||
|
||||
field.type === 'SIGNATURE'),
|
||||
insertFields && ((!field?.fieldMeta?.readOnly && Boolean(field.customText)) || field.type === 'SIGNATURE'),
|
||||
signature:
|
||||
field.signature && insertFields
|
||||
? {
|
||||
create: {
|
||||
recipientId,
|
||||
signatureImageAsBase64: isBase64Image(field.signature) ? field.signature : null,
|
||||
typedSignature: isBase64Image(field.signature) ? null : field.signature,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return await prisma.envelope.findFirstOrThrow({
|
||||
where: {
|
||||
id: createdEnvelope.id,
|
||||
},
|
||||
include: {
|
||||
recipients: true,
|
||||
envelopeItems: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const seedOverflowTestDocument = async ({
|
||||
userId,
|
||||
teamId,
|
||||
recipientName,
|
||||
recipientEmail,
|
||||
insertFields,
|
||||
status,
|
||||
}: {
|
||||
userId: number;
|
||||
teamId: number;
|
||||
recipientName: string;
|
||||
recipientEmail: string;
|
||||
insertFields: boolean;
|
||||
status: DocumentStatus;
|
||||
}) => {
|
||||
const overflowPdf = fs.readFileSync(path.join(__dirname, '../../../assets/field-overflow.pdf')).toString('base64');
|
||||
|
||||
const overflowDocumentData = await createDocumentData({ documentData: overflowPdf });
|
||||
|
||||
const secondaryId = await incrementDocumentId().then((v) => v.formattedDocumentId);
|
||||
|
||||
const documentMeta = await prisma.documentMeta.create({
|
||||
data: {},
|
||||
});
|
||||
|
||||
const createdEnvelope = await prisma.envelope.create({
|
||||
data: {
|
||||
id: prefixedId('envelope'),
|
||||
secondaryId,
|
||||
internalVersion: 2,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
documentMetaId: documentMeta.id,
|
||||
source: DocumentSource.DOCUMENT,
|
||||
title: 'Overflow Test',
|
||||
status,
|
||||
envelopeItems: {
|
||||
createMany: {
|
||||
data: [
|
||||
{
|
||||
id: prefixedId('envelope_item'),
|
||||
title: 'field-overflow',
|
||||
documentDataId: overflowDocumentData.id,
|
||||
order: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
userId,
|
||||
teamId,
|
||||
recipients: {
|
||||
create: {
|
||||
name: recipientName,
|
||||
email: recipientEmail,
|
||||
token: nanoid(),
|
||||
sendStatus: status === 'DRAFT' ? SendStatus.NOT_SENT : SendStatus.SENT,
|
||||
signingStatus: status === 'COMPLETED' ? SigningStatus.SIGNED : SigningStatus.NOT_SIGNED,
|
||||
readStatus: status !== 'DRAFT' ? ReadStatus.OPENED : ReadStatus.NOT_OPENED,
|
||||
},
|
||||
},
|
||||
},
|
||||
include: {
|
||||
recipients: true,
|
||||
envelopeItems: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { id, recipients, envelopeItems } = createdEnvelope;
|
||||
|
||||
const recipientId = recipients[0].id;
|
||||
const envelopeItemId = envelopeItems.find((item) => item.order === 1)?.id;
|
||||
|
||||
if (!envelopeItemId) {
|
||||
throw new Error('Envelope item not found');
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
OVERFLOW_TEST_FIELDS.map(async (field) => {
|
||||
// Use seedFieldMeta (full meta with all defaults) instead of fieldMeta
|
||||
// (minimal meta for API testing) since the seed bypasses API validation.
|
||||
const { fieldMeta: _fieldMeta, seedFieldMeta, ...fieldData } = field;
|
||||
|
||||
await prisma.field.create({
|
||||
data: {
|
||||
...fieldData,
|
||||
fieldMeta: seedFieldMeta,
|
||||
recipientId,
|
||||
envelopeItemId,
|
||||
envelopeId: id,
|
||||
customText: insertFields ? field.customText : '',
|
||||
inserted:
|
||||
insertFields && ((!seedFieldMeta?.readOnly && Boolean(field.customText)) || field.type === 'SIGNATURE'),
|
||||
signature:
|
||||
field.signature && insertFields
|
||||
? {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import { createTeamMembers } from '@documenso/trpc/server/team-router/create-team-members';
|
||||
import { TeamMemberRole } from '@prisma/client';
|
||||
|
||||
import { prisma } from '..';
|
||||
import { seedTeam } from './teams';
|
||||
|
||||
/**
|
||||
* One-off seed script: creates a team with a large number of members.
|
||||
*
|
||||
* Run via:
|
||||
* npm run with:env -- tsx packages/prisma/seed/large-team-seed.ts
|
||||
*
|
||||
* Produces:
|
||||
* - 1 owner
|
||||
* - ORG_MEMBER_COUNT organisation members
|
||||
* - TEAM_MEMBER_COUNT of those org members are also added to the team's role group
|
||||
*/
|
||||
|
||||
const ORG_MEMBER_COUNT = 200;
|
||||
const TEAM_MEMBER_COUNT = 50;
|
||||
|
||||
const seedLargeTeam = async () => {
|
||||
console.log(`[SEEDING]: Creating team with ${ORG_MEMBER_COUNT} organisation members...`);
|
||||
|
||||
const { owner, team, organisation } = await seedTeam({
|
||||
createTeamMembers: ORG_MEMBER_COUNT,
|
||||
});
|
||||
|
||||
// Exclude the owner — they're already a team member by default.
|
||||
const nonOwnerOrgMembers = organisation.members.filter((member) => member.userId !== owner.id);
|
||||
|
||||
const membersToAttachToTeam = nonOwnerOrgMembers.slice(0, TEAM_MEMBER_COUNT);
|
||||
|
||||
console.log(`[SEEDING]: Attaching ${membersToAttachToTeam.length} org members to the team's role group...`);
|
||||
|
||||
await createTeamMembers({
|
||||
userId: owner.id,
|
||||
teamId: team.id,
|
||||
membersToCreate: membersToAttachToTeam.map((member) => ({
|
||||
organisationMemberId: member.id,
|
||||
teamRole: TeamMemberRole.MEMBER,
|
||||
})),
|
||||
});
|
||||
|
||||
console.log(`[SEEDING]: Done.`);
|
||||
console.log(` Owner email: ${owner.email}`);
|
||||
console.log(` Owner password: password`);
|
||||
console.log(` Organisation: ${organisation.url} (id ${organisation.id})`);
|
||||
console.log(` Team URL: ${team.url} (id ${team.id})`);
|
||||
console.log(` Org members: ${ORG_MEMBER_COUNT}`);
|
||||
console.log(` Team-group members: ${membersToAttachToTeam.length}`);
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
await seedLargeTeam();
|
||||
} catch (err) {
|
||||
console.error('[SEEDING]: Failed to seed large team.');
|
||||
console.error(err);
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
void main();
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { OrganisationMemberRole, OrganisationType } from '@prisma/client';
|
||||
import { OrganisationGroupType, type User } from '@prisma/client';
|
||||
|
||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
||||
import { addUserToOrganisation } from '@documenso/lib/server-only/organisation/accept-organisation-invitation';
|
||||
import type { OrganisationMemberRole, OrganisationType } from '@prisma/client';
|
||||
import { OrganisationGroupType, type User } from '@prisma/client';
|
||||
|
||||
import { prisma } from '..';
|
||||
import { seedTestEmail } from './users';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
import { createTeamMembers } from '@documenso/trpc/server/team-router/create-team-members';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
import { prisma } from '..';
|
||||
import type { Prisma } from '../client';
|
||||
@@ -96,11 +95,7 @@ type SeedTeamMemberOptions = {
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export const seedTeamMember = async ({
|
||||
teamId,
|
||||
name,
|
||||
role = TeamMemberRole.ADMIN,
|
||||
}: SeedTeamMemberOptions) => {
|
||||
export const seedTeamMember = async ({ teamId, name, role = TeamMemberRole.ADMIN }: SeedTeamMemberOptions) => {
|
||||
const { user } = await seedUser({ name });
|
||||
|
||||
const team = await prisma.team.findFirstOrThrow({
|
||||
@@ -162,13 +157,7 @@ export const unseedTeamEmail = async ({ teamId }: { teamId: number }) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const seedTeamEmailVerification = async ({
|
||||
email,
|
||||
teamId,
|
||||
}: {
|
||||
email: string;
|
||||
teamId: number;
|
||||
}) => {
|
||||
export const seedTeamEmailVerification = async ({ email, teamId }: { email: string; teamId: number }) => {
|
||||
return await prisma.teamEmailVerification.create({
|
||||
data: {
|
||||
teamId,
|
||||
|
||||
@@ -20,9 +20,7 @@ import {
|
||||
SigningStatus,
|
||||
} from '../client';
|
||||
|
||||
const examplePdf = fs
|
||||
.readFileSync(path.join(__dirname, '../../../assets/example.pdf'))
|
||||
.toString('base64');
|
||||
const examplePdf = fs.readFileSync(path.join(__dirname, '../../../assets/example.pdf')).toString('base64');
|
||||
|
||||
type SeedTemplateOptions = {
|
||||
title?: string;
|
||||
@@ -37,11 +35,7 @@ type CreateTemplateOptions = {
|
||||
createTemplateOptions?: Partial<Prisma.EnvelopeUncheckedCreateInput>;
|
||||
};
|
||||
|
||||
export const seedBlankTemplate = async (
|
||||
owner: User,
|
||||
teamId: number,
|
||||
options: CreateTemplateOptions = {},
|
||||
) => {
|
||||
export const seedBlankTemplate = async (owner: User, teamId: number, options: CreateTemplateOptions = {}) => {
|
||||
const { key, createTemplateOptions = {} } = options;
|
||||
|
||||
const documentData = await prisma.documentData.create({
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { OrganisationType, Role } from '@prisma/client';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
||||
import { createPersonalOrganisation } from '@documenso/lib/server-only/organisation/create-organisation';
|
||||
import { OrganisationType, Role } from '@prisma/client';
|
||||
import { customAlphabet } from 'nanoid';
|
||||
|
||||
import { prisma } from '..';
|
||||
import { setOrganisationType } from './organisations';
|
||||
|
||||
Reference in New Issue
Block a user