mirror of
https://github.com/documenso/documenso.git
synced 2026-07-25 17:35:05 +10:00
chore: fix merge conflicts
This commit is contained in:
@@ -63,6 +63,7 @@ export class LocalJobProvider extends BaseJobProvider {
|
||||
jobId: pendingJob.id,
|
||||
jobDefinitionId: pendingJob.jobId,
|
||||
data: options,
|
||||
isRetry: false,
|
||||
});
|
||||
}),
|
||||
);
|
||||
@@ -198,6 +199,7 @@ export class LocalJobProvider extends BaseJobProvider {
|
||||
jobId,
|
||||
jobDefinitionId: backgroundJob.jobId,
|
||||
data: options,
|
||||
isRetry: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ const detectFieldsFromPage = async ({
|
||||
});
|
||||
|
||||
const result = await generateObject({
|
||||
model: vertex('gemini-3-pro-preview'),
|
||||
model: vertex('gemini-3-flash-preview'),
|
||||
system: SYSTEM_PROMPT,
|
||||
schema: ZSubmitDetectedFieldsInputSchema,
|
||||
messages,
|
||||
|
||||
@@ -207,7 +207,7 @@ const detectRecipientsFromImages = async ({
|
||||
});
|
||||
|
||||
const result = await generateObject({
|
||||
model: vertex('gemini-2.5-flash'),
|
||||
model: vertex('gemini-3-flash-preview'),
|
||||
system: SYSTEM_PROMPT,
|
||||
schema: ZDetectedRecipientsSchema,
|
||||
messages,
|
||||
|
||||
@@ -9,7 +9,10 @@ globalThis.Image = Image;
|
||||
|
||||
class SkiaCanvasFactory {
|
||||
_createCanvas(width: number, height: number) {
|
||||
return new Canvas(width, height);
|
||||
const canvas = new Canvas(width, height);
|
||||
canvas.gpu = false;
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
create(width: number, height: number) {
|
||||
@@ -44,10 +47,12 @@ export type PdfToImagesOptions = {
|
||||
export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOptions = {}) => {
|
||||
const { scale = 2 } = options;
|
||||
|
||||
const pdf = await pdfjsLib.getDocument({
|
||||
const task = await pdfjsLib.getDocument({
|
||||
data: pdfBytes,
|
||||
CanvasFactory: SkiaCanvasFactory,
|
||||
}).promise;
|
||||
});
|
||||
|
||||
const pdf = await task.promise;
|
||||
|
||||
const images = await pMap(
|
||||
Array.from({ length: pdf.numPages }),
|
||||
@@ -58,6 +63,8 @@ export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOpti
|
||||
const viewport = page.getViewport({ scale });
|
||||
|
||||
const canvas = new Canvas(viewport.width, viewport.height);
|
||||
canvas.gpu = false;
|
||||
|
||||
const canvasContext = canvas.getContext('2d');
|
||||
|
||||
await page.render({
|
||||
@@ -68,18 +75,23 @@ export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOpti
|
||||
viewport,
|
||||
}).promise;
|
||||
|
||||
return {
|
||||
const result = {
|
||||
pageNumber,
|
||||
image: await canvas.toBuffer('jpeg'),
|
||||
width: Math.floor(viewport.width),
|
||||
height: Math.floor(viewport.height),
|
||||
mimeType: 'image/jpeg',
|
||||
};
|
||||
|
||||
void page.cleanup();
|
||||
|
||||
return result;
|
||||
},
|
||||
{ concurrency: 10 },
|
||||
);
|
||||
|
||||
void pdf.destroy();
|
||||
void pdf.destroy().catch((e) => console.error(e));
|
||||
void task.destroy().catch((e) => console.error(e));
|
||||
|
||||
return images;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@ export const getDocumentCertificateAuditLogs = async ({
|
||||
DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_INSERTED,
|
||||
DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_OPENED,
|
||||
DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT,
|
||||
DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SENT,
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -37,6 +38,9 @@ export const getDocumentCertificateAuditLogs = async ({
|
||||
[DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_OPENED]: auditLogs.filter(
|
||||
(log) => log.type === DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_OPENED,
|
||||
),
|
||||
[DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SENT]: auditLogs.filter(
|
||||
(log) => log.type === DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SENT,
|
||||
),
|
||||
[DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_INSERTED]: auditLogs.filter(
|
||||
(log) => log.type === DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FIELD_INSERTED,
|
||||
),
|
||||
|
||||
@@ -81,6 +81,7 @@ export type CreateEnvelopeOptions = {
|
||||
globalActionAuth?: TDocumentActionAuthTypes[];
|
||||
recipients?: CreateEnvelopeRecipientOptions[];
|
||||
folderId?: string;
|
||||
delegatedDocumentOwner?: string;
|
||||
};
|
||||
attachments?: Array<{
|
||||
label: string;
|
||||
@@ -114,6 +115,7 @@ export const createEnvelope = async ({
|
||||
publicTitle,
|
||||
publicDescription,
|
||||
visibility: visibilityOverride,
|
||||
delegatedDocumentOwner,
|
||||
} = data;
|
||||
|
||||
const team = await prisma.team.findFirst({
|
||||
@@ -256,6 +258,43 @@ export const createEnvelope = async ({
|
||||
? await incrementDocumentId().then((v) => v.formattedDocumentId)
|
||||
: await incrementTemplateId().then((v) => v.formattedTemplateId);
|
||||
|
||||
const getValidatedDelegatedOwner = async () => {
|
||||
if (
|
||||
!settings.delegateDocumentOwnership ||
|
||||
!delegatedDocumentOwner ||
|
||||
requestMetadata.source === 'app'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const delegatedOwner = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: delegatedDocumentOwner,
|
||||
},
|
||||
});
|
||||
|
||||
if (!delegatedOwner) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Delegated document owner must be a member of the team',
|
||||
});
|
||||
}
|
||||
|
||||
const isTeamMember = await prisma.team.findFirst({
|
||||
where: buildTeamWhereQuery({ teamId, userId: delegatedOwner.id }),
|
||||
});
|
||||
|
||||
if (!isTeamMember) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Delegated document owner must be a member of the team',
|
||||
});
|
||||
}
|
||||
|
||||
return delegatedOwner;
|
||||
};
|
||||
|
||||
const delegatedOwner = await getValidatedDelegatedOwner();
|
||||
const envelopeOwnerId = delegatedOwner?.id ?? userId;
|
||||
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const envelope = await tx.envelope.create({
|
||||
data: {
|
||||
@@ -285,7 +324,7 @@ export const createEnvelope = async ({
|
||||
})),
|
||||
},
|
||||
},
|
||||
userId,
|
||||
userId: envelopeOwnerId,
|
||||
teamId,
|
||||
authOptions,
|
||||
visibility,
|
||||
@@ -393,6 +432,9 @@ export const createEnvelope = async ({
|
||||
data: createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_CREATED,
|
||||
envelopeId: envelope.id,
|
||||
user: {
|
||||
id: envelopeOwnerId,
|
||||
},
|
||||
metadata: requestMetadata,
|
||||
data: {
|
||||
title,
|
||||
@@ -403,6 +445,25 @@ export const createEnvelope = async ({
|
||||
}),
|
||||
});
|
||||
|
||||
// Create audit log for delegated owner if validation passed
|
||||
if (delegatedOwner) {
|
||||
await tx.documentAuditLog.create({
|
||||
data: createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_DELEGATED_OWNER_CREATED,
|
||||
envelopeId: envelope.id,
|
||||
user: {
|
||||
id: userId,
|
||||
},
|
||||
metadata: requestMetadata,
|
||||
data: {
|
||||
delegatedOwnerName: delegatedOwner.name,
|
||||
delegatedOwnerEmail: delegatedOwner.email,
|
||||
teamName: team.name,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
await triggerWebhook({
|
||||
event: WebhookTriggerEvents.DOCUMENT_CREATED,
|
||||
data: ZWebhookDocumentSchema.parse(mapEnvelopeToWebhookDocumentPayload(createdEnvelope)),
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
import type {
|
||||
DocumentSource,
|
||||
DocumentStatus,
|
||||
Envelope,
|
||||
EnvelopeType,
|
||||
Prisma,
|
||||
} from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { TEAM_DOCUMENT_VISIBILITY_MAP } from '../../constants/teams';
|
||||
import type { FindResultResponse } from '../../types/search-params';
|
||||
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
|
||||
import { getTeamById } from '../team/get-team';
|
||||
|
||||
export type FindEnvelopesOptions = {
|
||||
userId: number;
|
||||
teamId: number;
|
||||
type?: EnvelopeType;
|
||||
templateId?: number;
|
||||
source?: DocumentSource;
|
||||
status?: DocumentStatus;
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
orderBy?: {
|
||||
column: keyof Pick<Envelope, 'createdAt'>;
|
||||
direction: 'asc' | 'desc';
|
||||
};
|
||||
query?: string;
|
||||
folderId?: string;
|
||||
};
|
||||
|
||||
export const findEnvelopes = async ({
|
||||
userId,
|
||||
teamId,
|
||||
type,
|
||||
templateId,
|
||||
source,
|
||||
status,
|
||||
page = 1,
|
||||
perPage = 10,
|
||||
orderBy,
|
||||
query = '',
|
||||
folderId,
|
||||
}: FindEnvelopesOptions) => {
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
|
||||
const team = await getTeamById({
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
|
||||
const orderByColumn = orderBy?.column ?? 'createdAt';
|
||||
const orderByDirection = orderBy?.direction ?? 'desc';
|
||||
|
||||
const searchFilter: Prisma.EnvelopeWhereInput = query
|
||||
? {
|
||||
OR: [
|
||||
{ title: { contains: query, mode: 'insensitive' } },
|
||||
{ externalId: { contains: query, mode: 'insensitive' } },
|
||||
{ recipients: { some: { name: { contains: query, mode: 'insensitive' } } } },
|
||||
{ recipients: { some: { email: { contains: query, mode: 'insensitive' } } } },
|
||||
],
|
||||
}
|
||||
: {};
|
||||
|
||||
const visibilityFilter: Prisma.EnvelopeWhereInput = {
|
||||
visibility: {
|
||||
in: TEAM_DOCUMENT_VISIBILITY_MAP[team.currentTeamRole],
|
||||
},
|
||||
};
|
||||
|
||||
const teamEmailFilters: Prisma.EnvelopeWhereInput[] = [];
|
||||
|
||||
if (team.teamEmail) {
|
||||
teamEmailFilters.push(
|
||||
{
|
||||
user: {
|
||||
email: team.teamEmail.email,
|
||||
},
|
||||
},
|
||||
{
|
||||
recipients: {
|
||||
some: {
|
||||
email: team.teamEmail.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const whereClause: Prisma.EnvelopeWhereInput = {
|
||||
AND: [
|
||||
{
|
||||
OR: [
|
||||
{
|
||||
teamId: team.id,
|
||||
...visibilityFilter,
|
||||
},
|
||||
{
|
||||
userId,
|
||||
},
|
||||
...teamEmailFilters,
|
||||
],
|
||||
},
|
||||
{
|
||||
folderId: folderId ?? null,
|
||||
deletedAt: null,
|
||||
},
|
||||
searchFilter,
|
||||
],
|
||||
};
|
||||
|
||||
if (type) {
|
||||
whereClause.type = type;
|
||||
}
|
||||
|
||||
if (templateId) {
|
||||
whereClause.templateId = templateId;
|
||||
}
|
||||
|
||||
if (source) {
|
||||
whereClause.source = source;
|
||||
}
|
||||
|
||||
if (status) {
|
||||
whereClause.status = status;
|
||||
}
|
||||
|
||||
const [data, count] = await Promise.all([
|
||||
prisma.envelope.findMany({
|
||||
where: whereClause,
|
||||
skip: Math.max(page - 1, 0) * perPage,
|
||||
take: perPage,
|
||||
orderBy: {
|
||||
[orderByColumn]: orderByDirection,
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
recipients: {
|
||||
orderBy: {
|
||||
id: 'asc',
|
||||
},
|
||||
},
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
url: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.envelope.count({
|
||||
where: whereClause,
|
||||
}),
|
||||
]);
|
||||
|
||||
const maskedData = data.map((envelope) =>
|
||||
maskRecipientTokensForDocument({
|
||||
document: envelope,
|
||||
user,
|
||||
}),
|
||||
);
|
||||
|
||||
const mappedData = maskedData.map((envelope) => ({
|
||||
...envelope,
|
||||
recipients: envelope.Recipient,
|
||||
user: {
|
||||
id: envelope.user.id,
|
||||
name: envelope.user.name || '',
|
||||
email: envelope.user.email,
|
||||
},
|
||||
}));
|
||||
|
||||
return {
|
||||
data: mappedData,
|
||||
count,
|
||||
currentPage: Math.max(page, 1),
|
||||
perPage,
|
||||
totalPages: Math.ceil(count / perPage),
|
||||
} satisfies FindResultResponse<typeof mappedData>;
|
||||
};
|
||||
@@ -0,0 +1,213 @@
|
||||
import type { EnvelopeType, Prisma } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { TEAM_DOCUMENT_VISIBILITY_MAP } from '../../constants/teams';
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import type { EnvelopeIdsOptions } from '../../utils/envelope';
|
||||
import { unsafeBuildEnvelopeIdsQuery } from '../../utils/envelope';
|
||||
import { getTeamById } from '../team/get-team';
|
||||
|
||||
export type GetEnvelopesByIdsOptions = {
|
||||
/**
|
||||
* The envelope IDs to fetch with their type.
|
||||
*/
|
||||
ids: EnvelopeIdsOptions;
|
||||
|
||||
/**
|
||||
* The user ID who has been authenticated.
|
||||
*/
|
||||
userId: number;
|
||||
|
||||
/**
|
||||
* The unvalidated team ID from the request.
|
||||
*/
|
||||
teamId: number;
|
||||
|
||||
/**
|
||||
* The type of envelope to get.
|
||||
*
|
||||
* Set to null to bypass check.
|
||||
*/
|
||||
type: EnvelopeType | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches multiple envelopes by their IDs with proper access control.
|
||||
*
|
||||
* Only returns envelopes that the user has valid access to based on:
|
||||
* 1. Document ownership (userId matches)
|
||||
* 2. Team membership with appropriate visibility level
|
||||
* 3. Team email ownership
|
||||
*
|
||||
* NOTE: Be extremely careful when modifying this function. Needs at minimum two reviewers to approve any changes.
|
||||
*/
|
||||
export const getEnvelopesByIds = async ({
|
||||
ids,
|
||||
userId,
|
||||
teamId,
|
||||
type,
|
||||
}: GetEnvelopesByIdsOptions) => {
|
||||
const { envelopeWhereInput } = await getMultipleEnvelopeWhereInput({
|
||||
ids,
|
||||
userId,
|
||||
teamId,
|
||||
type,
|
||||
});
|
||||
|
||||
const envelopes = await prisma.envelope.findMany({
|
||||
where: envelopeWhereInput,
|
||||
include: {
|
||||
envelopeItems: {
|
||||
include: {
|
||||
documentData: true,
|
||||
},
|
||||
orderBy: {
|
||||
order: 'asc',
|
||||
},
|
||||
},
|
||||
folder: true,
|
||||
documentMeta: true,
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
recipients: {
|
||||
orderBy: {
|
||||
id: 'asc',
|
||||
},
|
||||
},
|
||||
fields: true,
|
||||
team: {
|
||||
select: {
|
||||
id: true,
|
||||
url: true,
|
||||
},
|
||||
},
|
||||
directLink: {
|
||||
select: {
|
||||
directTemplateRecipientId: true,
|
||||
enabled: true,
|
||||
id: true,
|
||||
token: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return envelopes.map((envelope) => ({
|
||||
...envelope,
|
||||
user: {
|
||||
id: envelope.user.id,
|
||||
name: envelope.user.name || '',
|
||||
email: envelope.user.email,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
export type GetEnvelopesByIdsResponse = Awaited<ReturnType<typeof getEnvelopesByIds>>;
|
||||
|
||||
export type GetMultipleEnvelopeWhereInputOptions = {
|
||||
/**
|
||||
* The envelope IDs to fetch with their type.
|
||||
*/
|
||||
ids: EnvelopeIdsOptions;
|
||||
|
||||
/**
|
||||
* The user ID who has been authenticated.
|
||||
*/
|
||||
userId: number;
|
||||
|
||||
/**
|
||||
* The unknown teamId from the request.
|
||||
*/
|
||||
teamId: number;
|
||||
|
||||
/**
|
||||
* The type of envelope to get.
|
||||
*
|
||||
* Set to null to bypass check.
|
||||
*/
|
||||
type: EnvelopeType | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate the where input for a multiple envelope Prisma query.
|
||||
*
|
||||
* This will return a query that allows a user to get documents if they have valid access to them.
|
||||
*
|
||||
* NOTE: Be extremely careful when modifying this function. Needs at minimum two reviewers to approve any changes.
|
||||
*/
|
||||
export const getMultipleEnvelopeWhereInput = async ({
|
||||
ids,
|
||||
userId,
|
||||
teamId,
|
||||
type,
|
||||
}: GetMultipleEnvelopeWhereInputOptions) => {
|
||||
// Backup validation incase something goes wrong.
|
||||
if (!ids.ids || !userId || !teamId || type === undefined) {
|
||||
console.error(`[CRTICAL ERROR]: MUST NEVER HAPPEN`);
|
||||
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Envelope IDs not found',
|
||||
});
|
||||
}
|
||||
|
||||
// Validate that the user belongs to the team provided.
|
||||
const team = await getTeamById({ teamId, userId });
|
||||
|
||||
const envelopeOrInput: Prisma.EnvelopeWhereInput[] = [
|
||||
// Allow access if they own the document.
|
||||
{
|
||||
userId,
|
||||
},
|
||||
// Or, if they belong to the team that the document is associated with.
|
||||
{
|
||||
visibility: {
|
||||
in: TEAM_DOCUMENT_VISIBILITY_MAP[team.currentTeamRole],
|
||||
},
|
||||
teamId: team.id,
|
||||
},
|
||||
];
|
||||
|
||||
// Allow access to documents sent from the team email.
|
||||
if (team.teamEmail) {
|
||||
envelopeOrInput.push({
|
||||
user: {
|
||||
email: team.teamEmail.email,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
// NOTE: DO NOT PUT ANY CODE AFTER THIS POINT.
|
||||
// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
const envelopeWhereInput: Prisma.EnvelopeWhereInput = {
|
||||
...unsafeBuildEnvelopeIdsQuery(ids, type),
|
||||
OR: envelopeOrInput,
|
||||
};
|
||||
|
||||
// Final backup validation incase something goes wrong.
|
||||
if (
|
||||
!envelopeWhereInput.OR ||
|
||||
envelopeWhereInput.OR.length < 2 ||
|
||||
!userId ||
|
||||
!teamId ||
|
||||
!team.id ||
|
||||
teamId !== team.id
|
||||
) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Query not valid',
|
||||
});
|
||||
}
|
||||
|
||||
// Do not modify this return directly, all adjustments need to be made prior to the above if statement.
|
||||
return {
|
||||
envelopeWhereInput,
|
||||
team,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { deletedAccountServiceAccount } from '../user/service-accounts/deleted-account';
|
||||
|
||||
export type OrphanEnvelopesOptions = {
|
||||
teamId: number;
|
||||
};
|
||||
|
||||
export const orphanEnvelopes = async ({ teamId }: OrphanEnvelopesOptions) => {
|
||||
const serviceAccount = await deletedAccountServiceAccount();
|
||||
|
||||
// Transfer all inflight and completed envelopes to the service account.
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
deletedAt: null,
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
teamId: serviceAccount.ownedOrganisations[0].teams[0].id,
|
||||
deletedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Transfer any remaining deleted envelopes to the service account.
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
teamId: serviceAccount.ownedOrganisations[0].teams[0].id,
|
||||
},
|
||||
});
|
||||
|
||||
// Then delete anything remaining across documents and templates.
|
||||
await prisma.envelope.deleteMany({
|
||||
where: {
|
||||
teamId,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type TransferTeamEnvelopesOptions = {
|
||||
sourceTeamId: number;
|
||||
targetTeamId: number;
|
||||
};
|
||||
|
||||
export const transferTeamEnvelopes = async ({
|
||||
sourceTeamId,
|
||||
targetTeamId,
|
||||
}: TransferTeamEnvelopesOptions) => {
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
teamId: sourceTeamId,
|
||||
},
|
||||
data: {
|
||||
teamId: targetTeamId,
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* !: This is a workaround to fix the memory leak in the skia-canvas library.
|
||||
* !: Internals are ported from the original `konva/skia-backend.js` file.
|
||||
*/
|
||||
import { Konva } from 'konva/lib/_CoreInternals';
|
||||
import { Canvas, DOMMatrix, Image, Path2D } from 'skia-canvas';
|
||||
|
||||
// @ts-expect-error skia-canvas satisfies the requirements
|
||||
global.DOMMatrix = DOMMatrix;
|
||||
|
||||
// @ts-expect-error skia-canvas satisfies the requirements
|
||||
global.Path2D = Path2D;
|
||||
Path2D.prototype.toString = () => '[object Path2D]';
|
||||
|
||||
Konva.Util['createCanvasElement'] = () => {
|
||||
const node = new Canvas(300, 300);
|
||||
node.gpu = false;
|
||||
|
||||
if (!('style' in node) || !node['style']) {
|
||||
Object.assign(node, { style: {} });
|
||||
}
|
||||
|
||||
node.toString = () => '[object HTMLCanvasElement]';
|
||||
const ctx = node.getContext('2d');
|
||||
|
||||
Object.defineProperty(ctx, 'canvas', {
|
||||
get: () => node,
|
||||
});
|
||||
|
||||
return node as unknown as HTMLCanvasElement;
|
||||
};
|
||||
|
||||
Konva.Util.createImageElement = () => {
|
||||
const node = new Image();
|
||||
node.toString = () => '[object HTMLImageElement]';
|
||||
|
||||
return node as unknown as HTMLImageElement;
|
||||
};
|
||||
|
||||
Konva._renderBackend = 'skia-canvas';
|
||||
|
||||
export default Konva;
|
||||
@@ -40,7 +40,10 @@ export const acceptOrganisationInvitation = async ({
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: organisationMemberInvite.email,
|
||||
email: {
|
||||
equals: organisationMemberInvite.email,
|
||||
mode: 'insensitive',
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
|
||||
@@ -4,8 +4,10 @@ import {
|
||||
PDFDict,
|
||||
type PDFDocument,
|
||||
PDFName,
|
||||
PDFNumber,
|
||||
PDFRadioGroup,
|
||||
PDFRef,
|
||||
PDFStream,
|
||||
drawObject,
|
||||
popGraphicsState,
|
||||
pushGraphicsState,
|
||||
@@ -103,6 +105,36 @@ const getAppearanceRefForWidget = (field: PDFField, widget: PDFWidgetAnnotation)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensures that an appearance stream has the required dictionary entries to be
|
||||
* used as a Form XObject. Some PDFs have appearance streams that are missing
|
||||
* the /Subtype /Form entry, which causes Adobe Reader to fail to render them.
|
||||
*
|
||||
* Per PDF spec, a Form XObject stream requires:
|
||||
* - /Subtype /Form (required)
|
||||
* - /BBox (required, but should already exist for appearance streams)
|
||||
* - /FormType 1 (optional, defaults to 1)
|
||||
*/
|
||||
const normalizeAppearanceStream = (document: PDFDocument, appearanceRef: PDFRef) => {
|
||||
const appearanceStream = document.context.lookup(appearanceRef);
|
||||
|
||||
if (!(appearanceStream instanceof PDFStream)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dict = appearanceStream.dict;
|
||||
|
||||
// Ensure /Subtype /Form is set (required for XObject Form)
|
||||
if (!dict.has(PDFName.of('Subtype'))) {
|
||||
dict.set(PDFName.of('Subtype'), PDFName.of('Form'));
|
||||
}
|
||||
|
||||
// Ensure /FormType is set (optional, but good practice)
|
||||
if (!dict.has(PDFName.of('FormType'))) {
|
||||
dict.set(PDFName.of('FormType'), PDFNumber.of(1));
|
||||
}
|
||||
};
|
||||
|
||||
const flattenWidget = (document: PDFDocument, field: PDFField, widget: PDFWidgetAnnotation) => {
|
||||
try {
|
||||
const page = getPageForWidget(document, widget);
|
||||
@@ -117,6 +149,9 @@ const flattenWidget = (document: PDFDocument, field: PDFField, widget: PDFWidget
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the appearance stream has required XObject Form dictionary entries
|
||||
normalizeAppearanceStream(document, appearanceRef);
|
||||
|
||||
const xObjectKey = page.node.newXObject('FlatWidget', appearanceRef);
|
||||
|
||||
const rectangle = widget.getRectangle();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// sort-imports-ignore
|
||||
import 'konva/skia-backend';
|
||||
import '../konva/skia-backend';
|
||||
|
||||
import Konva from 'konva';
|
||||
import path from 'node:path';
|
||||
@@ -23,6 +23,7 @@ export const insertFieldInPDFV2 = async ({
|
||||
}: InsertFieldInPDFV2Options) => {
|
||||
const fontPath = path.join(process.cwd(), 'public/fonts');
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
FontLibrary.use({
|
||||
['Caveat']: [path.join(fontPath, 'caveat.ttf')],
|
||||
['Noto Sans']: [path.join(fontPath, 'noto-sans.ttf')],
|
||||
@@ -31,8 +32,8 @@ export const insertFieldInPDFV2 = async ({
|
||||
['Noto Sans Korean']: [path.join(fontPath, 'noto-sans-korean.ttf')],
|
||||
});
|
||||
|
||||
const stage = new Konva.Stage({ width: pageWidth, height: pageHeight });
|
||||
const layer = new Konva.Layer();
|
||||
let stage: Konva.Stage | null = new Konva.Stage({ width: pageWidth, height: pageHeight });
|
||||
let layer: Konva.Layer | null = new Konva.Layer();
|
||||
|
||||
// Render the fields onto the layer.
|
||||
for (const field of fields) {
|
||||
@@ -60,5 +61,13 @@ export const insertFieldInPDFV2 = async ({
|
||||
const canvas = layer.canvas._canvas as unknown as Canvas;
|
||||
|
||||
// Embed the SVG into the PDF
|
||||
return await canvas.toBuffer('pdf');
|
||||
const pdf = await canvas.toBuffer('pdf');
|
||||
|
||||
stage.destroy();
|
||||
layer.destroy();
|
||||
|
||||
stage = null;
|
||||
layer = null;
|
||||
|
||||
return pdf;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { hashString } from '../auth/hash';
|
||||
|
||||
export const getApiTokenByToken = async ({ token }: { token: string }) => {
|
||||
@@ -38,11 +39,17 @@ export const getApiTokenByToken = async ({ token }: { token: string }) => {
|
||||
});
|
||||
|
||||
if (!apiToken) {
|
||||
throw new Error('Invalid token');
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Invalid token',
|
||||
statusCode: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if (apiToken.expires && apiToken.expires < new Date()) {
|
||||
throw new Error('Expired token');
|
||||
throw new AppError(AppErrorCode.EXPIRED_CODE, {
|
||||
message: 'Expired token',
|
||||
statusCode: 401,
|
||||
});
|
||||
}
|
||||
|
||||
// Handle a silly choice from many moons ago
|
||||
@@ -54,7 +61,10 @@ export const getApiTokenByToken = async ({ token }: { token: string }) => {
|
||||
|
||||
// This will never happen but we need to narrow types
|
||||
if (!user) {
|
||||
throw new Error('Invalid token');
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Invalid token',
|
||||
statusCode: 401,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { hashString } from '../auth/hash';
|
||||
|
||||
export const getUserByApiToken = async ({ token }: { token: string }) => {
|
||||
@@ -19,14 +20,20 @@ export const getUserByApiToken = async ({ token }: { token: string }) => {
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error('Invalid token');
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Invalid token',
|
||||
statusCode: 401,
|
||||
});
|
||||
}
|
||||
|
||||
const retrievedToken = user.apiTokens.find((apiToken) => apiToken.token === hashedToken);
|
||||
|
||||
// This should be impossible but we need to satisfy TypeScript
|
||||
if (!retrievedToken) {
|
||||
throw new Error('Invalid token');
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'Invalid token',
|
||||
statusCode: 401,
|
||||
});
|
||||
}
|
||||
|
||||
if (retrievedToken.expires && retrievedToken.expires < new Date()) {
|
||||
|
||||
@@ -185,7 +185,7 @@ export const createDocumentFromDirectTemplate = async ({
|
||||
documentAuth: directTemplateEnvelope.authOptions,
|
||||
});
|
||||
|
||||
const directRecipientName = user?.name || initialDirectRecipientName;
|
||||
let directRecipientName = user?.name || initialDirectRecipientName;
|
||||
|
||||
// Ensure typesafety when we add more options.
|
||||
const isAccessAuthValid = match(derivedRecipientAccessAuth.at(0))
|
||||
@@ -238,7 +238,7 @@ export const createDocumentFromDirectTemplate = async ({
|
||||
}
|
||||
|
||||
if (templateField.type === FieldType.NAME && directRecipientName === undefined) {
|
||||
directRecipientName === signedFieldValue?.value;
|
||||
directRecipientName = signedFieldValue?.value;
|
||||
}
|
||||
|
||||
const derivedRecipientActionAuth = await validateFieldAuth({
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { deletedAccountServiceAccount } from './service-accounts/deleted-account';
|
||||
import { orphanEnvelopes } from '../envelope/orphan-envelopes';
|
||||
|
||||
export type DeleteUserOptions = {
|
||||
id: number;
|
||||
@@ -14,6 +12,30 @@ export const deleteUser = async ({ id }: DeleteUserOptions) => {
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
include: {
|
||||
ownedOrganisations: {
|
||||
include: {
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
organisationMember: {
|
||||
include: {
|
||||
organisation: {
|
||||
include: {
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
@@ -22,22 +44,36 @@ export const deleteUser = async ({ id }: DeleteUserOptions) => {
|
||||
});
|
||||
}
|
||||
|
||||
const serviceAccount = await deletedAccountServiceAccount();
|
||||
// Get team IDs from organisations the user owns.
|
||||
const ownedTeamIds = user.ownedOrganisations.flatMap((org) => org.teams.map((team) => team.id));
|
||||
|
||||
// TODO: Send out cancellations for all pending docs
|
||||
await prisma.envelope.updateMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
status: {
|
||||
in: [DocumentStatus.PENDING, DocumentStatus.REJECTED, DocumentStatus.COMPLETED],
|
||||
},
|
||||
},
|
||||
data: {
|
||||
userId: serviceAccount.id,
|
||||
deletedAt: new Date(),
|
||||
},
|
||||
});
|
||||
// Get team IDs from organisations the user is a member of (but not owner).
|
||||
const memberTeams = user.organisationMember
|
||||
.filter((member) => member.organisation.ownerUserId !== user.id)
|
||||
.flatMap((member) =>
|
||||
member.organisation.teams.map((team) => ({
|
||||
teamId: team.id,
|
||||
orgOwnerId: member.organisation.ownerUserId,
|
||||
})),
|
||||
);
|
||||
|
||||
// For teams where user is the org owner - orphan their envelopes.
|
||||
await Promise.all(ownedTeamIds.map(async (teamId) => orphanEnvelopes({ teamId })));
|
||||
|
||||
// For teams where user is a member (not owner) - transfer envelopes to team owner.
|
||||
await Promise.all(
|
||||
memberTeams.map(async ({ teamId, orgOwnerId }) => {
|
||||
return prisma.envelope.updateMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
teamId,
|
||||
},
|
||||
data: {
|
||||
userId: orgOwnerId,
|
||||
},
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return await prisma.user.delete({
|
||||
where: {
|
||||
|
||||
@@ -5,6 +5,20 @@ export const deletedAccountServiceAccount = async () => {
|
||||
where: {
|
||||
email: 'deleted-account@documenso.com',
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
ownedOrganisations: {
|
||||
select: {
|
||||
id: true,
|
||||
teams: {
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!serviceAccount) {
|
||||
|
||||
+267
-177
File diff suppressed because it is too large
Load Diff
@@ -96,6 +96,11 @@ msgstr "{0, plural, one {# field} other {# fields}}"
|
||||
msgid "{0, plural, one {# folder} other {# folders}}"
|
||||
msgstr "{0, plural, one {# folder} other {# folders}}"
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0, plural, one {# recipient have been added from AI detection.} other {# recipients have been added from AI detection.}}"
|
||||
msgstr "{0, plural, one {# recipient have been added from AI detection.} other {# recipients have been added from AI detection.}}"
|
||||
|
||||
#. placeholder {0}: template.recipients.length
|
||||
#: apps/remix/app/routes/_recipient+/d.$token+/_index.tsx
|
||||
msgid "{0, plural, one {# recipient} other {# recipients}}"
|
||||
@@ -146,11 +151,44 @@ msgstr "{0, plural, one {1 matching field} other {# matching fields}}"
|
||||
msgid "{0, plural, one {1 Recipient} other {# Recipients}}"
|
||||
msgstr "{0, plural, one {1 Recipient} other {# Recipients}}"
|
||||
|
||||
#. placeholder {0}: progress.fieldsDetected
|
||||
#. placeholder {1}: progress.pagesProcessed
|
||||
#. placeholder {2}: progress.totalPages
|
||||
#. placeholder {3}: progress.pagesProcessed
|
||||
#. placeholder {4}: progress.totalPages
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "{0, plural, one {Page {1} of {2} - # field found} other {Page {3} of {4} - # fields found}}"
|
||||
msgstr "{0, plural, one {Page {1} of {2} - # field found} other {Page {3} of {4} - # fields found}}"
|
||||
|
||||
#. placeholder {0}: progress.recipientsDetected
|
||||
#. placeholder {1}: progress.pagesProcessed
|
||||
#. placeholder {2}: progress.totalPages
|
||||
#. placeholder {3}: progress.pagesProcessed
|
||||
#. placeholder {4}: progress.totalPages
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "{0, plural, one {Page {1} of {2} - # recipient found} other {Page {3} of {4} - # recipients found}}"
|
||||
msgstr "{0, plural, one {Page {1} of {2} - # recipient found} other {Page {3} of {4} - # recipients found}}"
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0, plural, one {Recipient added} other {Recipients added}}"
|
||||
msgstr "{0, plural, one {Recipient added} other {Recipients added}}"
|
||||
|
||||
#. placeholder {0}: pendingRecipients.length
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx
|
||||
msgid "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
||||
msgstr "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
||||
|
||||
#. placeholder {0}: detectedFields.length
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "{0, plural, one {We found # field in your document.} other {We found # fields in your document.}}"
|
||||
msgstr "{0, plural, one {We found # field in your document.} other {We found # fields in your document.}}"
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "{0, plural, one {We found # recipient in your document.} other {We found # recipients in your document.}}"
|
||||
msgstr "{0, plural, one {We found # recipient in your document.} other {We found # recipients in your document.}}"
|
||||
|
||||
#. placeholder {0}: _(FRIENDLY_FIELD_TYPE[fieldType as FieldType])
|
||||
#. placeholder {0}: route.label
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx
|
||||
@@ -195,11 +233,6 @@ msgstr "{0} of {1} documents remaining this month."
|
||||
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||
msgstr "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0} recipient(s) have been added from AI detection."
|
||||
msgstr "{0} recipient(s) have been added from AI detection."
|
||||
|
||||
#. placeholder {0}: organisation.name
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "{0} Teams"
|
||||
@@ -846,9 +879,6 @@ msgid "A request to use your email has been initiated by {0} on Documenso"
|
||||
msgstr "A request to use your email has been initiated by {0} on Documenso"
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
msgid "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso"
|
||||
msgstr "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso"
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
msgid "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso."
|
||||
msgstr "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso."
|
||||
@@ -1283,6 +1313,10 @@ msgstr "After submission, a document will be automatically generated and added t
|
||||
msgid "AI Features"
|
||||
msgstr "AI Features"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them."
|
||||
msgstr "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them."
|
||||
|
||||
#: apps/remix/app/components/general/document/document-status.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx
|
||||
msgid "All"
|
||||
@@ -2260,6 +2294,10 @@ msgstr "Charts"
|
||||
msgid "Checkbox"
|
||||
msgstr "Checkbox"
|
||||
|
||||
#: packages/ui/primitives/document-flow/field-content.tsx
|
||||
msgid "Checkbox option"
|
||||
msgstr "Checkbox option"
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx
|
||||
msgid "Checkbox Settings"
|
||||
msgstr "Checkbox Settings"
|
||||
@@ -2363,6 +2401,7 @@ msgstr "Client Secret"
|
||||
msgid "Client secret is required"
|
||||
msgstr "Client secret is required"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
@@ -2375,7 +2414,6 @@ msgstr "Client secret is required"
|
||||
#: apps/remix/app/components/dialogs/team-group-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-group-update-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-member-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-use-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-test-dialog.tsx
|
||||
@@ -2386,7 +2424,9 @@ msgstr "Client secret is required"
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auth-2fa.tsx
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auth-passkey.tsx
|
||||
#: apps/remix/app/components/general/document/document-recipient-link-copy-dialog.tsx
|
||||
#: packages/ui/primitives/dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx
|
||||
#: packages/ui/primitives/sheet.tsx
|
||||
msgid "Close"
|
||||
msgstr "Close"
|
||||
|
||||
@@ -3064,6 +3104,10 @@ msgstr "Default Time Zone"
|
||||
msgid "Default Value"
|
||||
msgstr "Default Value"
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Delegate Document Ownership"
|
||||
msgstr "Delegate Document Ownership"
|
||||
|
||||
#: apps/remix/app/components/dialogs/document-delete-dialog.tsx
|
||||
msgid "delete"
|
||||
msgstr "delete"
|
||||
@@ -3283,8 +3327,8 @@ msgid "Device"
|
||||
msgstr "Device"
|
||||
|
||||
#: packages/email/templates/reset-password.tsx
|
||||
msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us.</0>"
|
||||
msgstr "Didn't request a password change? We are here to help you secure your account, just <0>contact us.</0>"
|
||||
msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us</0>."
|
||||
msgstr "Didn't request a password change? We are here to help you secure your account, just <0>contact us</0>."
|
||||
|
||||
#: apps/remix/app/components/general/template/template-direct-link-badge.tsx
|
||||
#: apps/remix/app/components/tables/templates-table.tsx
|
||||
@@ -3627,6 +3671,11 @@ msgctxt "Audit log format"
|
||||
msgid "Document opened"
|
||||
msgstr "Document opened"
|
||||
|
||||
#: packages/lib/utils/document-audit-logs.ts
|
||||
msgctxt "Audit log format"
|
||||
msgid "Document ownership delegated"
|
||||
msgstr "Document ownership delegated"
|
||||
|
||||
#: apps/remix/app/components/general/document/document-status.tsx
|
||||
msgid "Document pending"
|
||||
msgstr "Document pending"
|
||||
@@ -3825,6 +3874,11 @@ msgstr "Domain Name"
|
||||
msgid "Don't have an account? <0>Sign up</0>"
|
||||
msgstr "Don't have an account? <0>Sign up</0>"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
msgid "Don't transfer (Delete all documents)"
|
||||
msgstr "Don't transfer (Delete all documents)"
|
||||
|
||||
#: apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx
|
||||
#: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-certificate-qr-view.tsx
|
||||
@@ -3963,6 +4017,7 @@ msgstr "E.g. 100"
|
||||
#: apps/remix/app/components/general/document/document-page-view-button.tsx
|
||||
#: apps/remix/app/components/general/document/document-page-view-dropdown.tsx
|
||||
#: apps/remix/app/components/general/teams/team-email-dropdown.tsx
|
||||
#: apps/remix/app/components/tables/admin-dashboard-users-table.tsx
|
||||
#: apps/remix/app/components/tables/documents-table-action-button.tsx
|
||||
#: apps/remix/app/components/tables/documents-table-action-dropdown.tsx
|
||||
#: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
|
||||
@@ -4179,6 +4234,15 @@ msgstr "Enable account"
|
||||
msgid "Enable Account"
|
||||
msgstr "Enable Account"
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "Enable AI detection"
|
||||
msgstr "Enable AI detection"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Enable AI features"
|
||||
msgstr "Enable AI features"
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Enable AI-powered features such as automatic recipient detection. When enabled, document content will be sent to AI providers. We only use providers that do not retain data for training and prefer European regions where available."
|
||||
msgstr "Enable AI-powered features such as automatic recipient detection. When enabled, document content will be sent to AI providers. We only use providers that do not retain data for training and prefer European regions where available."
|
||||
@@ -4219,6 +4283,10 @@ msgstr "Enable signing order"
|
||||
msgid "Enable SSO portal"
|
||||
msgstr "Enable SSO portal"
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Enable team API tokens to delegate document ownership to another team member."
|
||||
msgstr "Enable team API tokens to delegate document ownership to another team member."
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
@@ -4817,10 +4885,26 @@ msgstr "Go home"
|
||||
msgid "Go to document"
|
||||
msgstr "Go to document"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to first page"
|
||||
msgstr "Go to first page"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to last page"
|
||||
msgstr "Go to last page"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to next page"
|
||||
msgstr "Go to next page"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx
|
||||
msgid "Go to owner"
|
||||
msgstr "Go to owner"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to previous page"
|
||||
msgstr "Go to previous page"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Go to team"
|
||||
msgstr "Go to team"
|
||||
@@ -4901,8 +4985,8 @@ msgid "Here you can set branding preferences for your organisation. Teams will i
|
||||
msgstr "Here you can set branding preferences for your organisation. Teams will inherit these settings by default."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx
|
||||
msgid "Here you can set branding preferences for your team"
|
||||
msgstr "Here you can set branding preferences for your team"
|
||||
msgid "Here you can set branding preferences for your team."
|
||||
msgstr "Here you can set branding preferences for your team."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.document.tsx
|
||||
msgid "Here you can set document preferences for your organisation. Teams will inherit these settings by default."
|
||||
@@ -4917,12 +5001,12 @@ msgid "Here you can set preferences and defaults for your team."
|
||||
msgstr "Here you can set preferences and defaults for your team."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx
|
||||
msgid "Here you can set your general branding preferences"
|
||||
msgstr "Here you can set your general branding preferences"
|
||||
msgid "Here you can set your general branding preferences."
|
||||
msgstr "Here you can set your general branding preferences."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.document.tsx
|
||||
msgid "Here you can set your general document preferences"
|
||||
msgstr "Here you can set your general document preferences"
|
||||
msgid "Here you can set your general document preferences."
|
||||
msgstr "Here you can set your general document preferences."
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
msgid "Here's how it works:"
|
||||
@@ -5087,6 +5171,7 @@ msgstr "Inherit authentication method"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/email-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/email-preferences-form.tsx
|
||||
msgid "Inherit from organisation"
|
||||
@@ -5479,6 +5564,7 @@ msgid "Looking for signature fields"
|
||||
msgstr "Looking for signature fields"
|
||||
|
||||
#: apps/remix/app/components/tables/admin-organisations-table.tsx
|
||||
#: apps/remix/app/components/tables/organisation-groups-table.tsx
|
||||
#: apps/remix/app/components/tables/organisation-teams-table.tsx
|
||||
#: apps/remix/app/components/tables/user-organisations-table.tsx
|
||||
msgid "Manage"
|
||||
@@ -5539,6 +5625,10 @@ msgstr "Manage linked accounts"
|
||||
msgid "Manage organisation"
|
||||
msgstr "Manage organisation"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Manage Organisation"
|
||||
msgstr "Manage Organisation"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx
|
||||
msgid "Manage organisations"
|
||||
msgstr "Manage organisations"
|
||||
@@ -5702,15 +5792,15 @@ msgstr "Member Since"
|
||||
msgid "Members"
|
||||
msgstr "Members"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/forms/support-ticket-form.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Message"
|
||||
msgstr "Message"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Message <0>(Optional)</0>"
|
||||
msgstr "Message <0>(Optional)</0>"
|
||||
|
||||
@@ -5860,10 +5950,6 @@ msgstr "Never expire"
|
||||
msgid "New Password"
|
||||
msgstr "New Password"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "New Template"
|
||||
msgstr "New Template"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-group-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-member-create-dialog.tsx
|
||||
#: apps/remix/app/components/embed/embed-direct-template-client-page.tsx
|
||||
@@ -5889,6 +5975,7 @@ msgstr "Next Recipient Name"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
||||
@@ -6096,8 +6183,8 @@ msgid "Once you have scanned the QR code or entered the code manually, enter the
|
||||
msgstr "Once you have scanned the QR code or entered the code manually, enter the code provided by your authenticator app below."
|
||||
|
||||
#: apps/remix/app/components/dialogs/organisation-email-domain-records-dialog.tsx
|
||||
msgid "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button"
|
||||
msgstr "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button"
|
||||
msgid "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button."
|
||||
msgstr "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button."
|
||||
|
||||
#: packages/lib/constants/template.ts
|
||||
msgid "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
|
||||
@@ -6131,6 +6218,10 @@ msgstr "Only PDF files are allowed"
|
||||
msgid "Oops! Something went wrong."
|
||||
msgstr "Oops! Something went wrong."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Open menu"
|
||||
msgstr "Open menu"
|
||||
|
||||
#: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx
|
||||
msgid "Opened"
|
||||
msgstr "Opened"
|
||||
@@ -6324,20 +6415,6 @@ msgstr "Ownership transferred to {organisationMemberName}."
|
||||
msgid "Page {0} of {1}"
|
||||
msgstr "Page {0} of {1}"
|
||||
|
||||
#. placeholder {0}: progress.pagesProcessed
|
||||
#. placeholder {1}: progress.totalPages
|
||||
#. placeholder {2}: progress.fieldsDetected
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "Page {0} of {1} - {2} field(s) found"
|
||||
msgstr "Page {0} of {1} - {2} field(s) found"
|
||||
|
||||
#. placeholder {0}: progress.pagesProcessed
|
||||
#. placeholder {1}: progress.totalPages
|
||||
#. placeholder {2}: progress.recipientsDetected
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "Page {0} of {1} - {2} recipient(s) found"
|
||||
msgstr "Page {0} of {1} - {2} recipient(s) found"
|
||||
|
||||
#. placeholder {0}: i + 1
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/primitives/pdf-viewer/base.tsx
|
||||
@@ -6683,10 +6760,6 @@ msgstr "Please try a different domain."
|
||||
msgid "Please try again and make sure you enter the correct email address."
|
||||
msgstr "Please try again and make sure you enter the correct email address."
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "Please try again later."
|
||||
msgstr "Please try again later."
|
||||
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/primitives/pdf-viewer/base.tsx
|
||||
@@ -6964,10 +7037,6 @@ msgstr "Recipient updated"
|
||||
msgid "Recipients"
|
||||
msgstr "Recipients"
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "Recipients added"
|
||||
msgstr "Recipients added"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/stats.tsx
|
||||
msgid "Recipients metrics"
|
||||
msgstr "Recipients metrics"
|
||||
@@ -7141,8 +7210,8 @@ msgstr "Reply to email"
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Reply To Email"
|
||||
msgstr "Reply To Email"
|
||||
msgid "Reply To Email <0>(Optional)</0>"
|
||||
msgstr "Reply To Email <0>(Optional)</0>"
|
||||
|
||||
#: apps/remix/app/components/general/webhook-logs-sheet.tsx
|
||||
msgid "Request"
|
||||
@@ -7279,6 +7348,11 @@ msgstr "Retry"
|
||||
msgid "Return"
|
||||
msgstr "Return"
|
||||
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/rejected.tsx
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/waiting.tsx
|
||||
msgid "Return Home"
|
||||
msgstr "Return Home"
|
||||
|
||||
#: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx
|
||||
msgid "Return to Documenso sign in page here"
|
||||
msgstr "Return to Documenso sign in page here"
|
||||
@@ -7445,6 +7519,7 @@ msgid "See the background jobs tab for the status"
|
||||
msgstr "See the background jobs tab for the status"
|
||||
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx
|
||||
#: packages/ui/primitives/document-flow/field-content.tsx
|
||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx
|
||||
#: packages/ui/primitives/document-flow/types.ts
|
||||
msgid "Select"
|
||||
@@ -8084,7 +8159,6 @@ msgstr "Some signers have not been assigned a signature field. Please assign at
|
||||
#: apps/remix/app/components/dialogs/team-email-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-inherit-member-disable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-inherit-member-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
@@ -8247,14 +8321,14 @@ msgstr "Stripe customer created successfully"
|
||||
msgid "Stripe Customer ID"
|
||||
msgstr "Stripe Customer ID"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/forms/support-ticket-form.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
msgid "Subject"
|
||||
msgstr "Subject"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Subject <0>(Optional)</0>"
|
||||
msgstr "Subject <0>(Optional)</0>"
|
||||
@@ -8575,7 +8649,6 @@ msgstr "Teams that this organisation group is currently assigned to"
|
||||
msgid "Template"
|
||||
msgstr "Template"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: packages/ui/primitives/document-upload-button.tsx
|
||||
msgid "Template (Legacy)"
|
||||
msgstr "Template (Legacy)"
|
||||
@@ -8588,7 +8661,7 @@ msgstr "Template Created"
|
||||
msgid "Template deleted"
|
||||
msgstr "Template deleted"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Template document uploaded"
|
||||
msgstr "Template document uploaded"
|
||||
|
||||
@@ -8650,10 +8723,6 @@ msgstr "Template uploaded"
|
||||
msgid "Templates"
|
||||
msgstr "Templates"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields."
|
||||
msgstr "Templates allow you to quickly generate documents with pre-filled recipients and fields."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
@@ -8787,6 +8856,12 @@ msgstr "The document owner has been notified of this rejection. No further actio
|
||||
msgid "The document owner has been notified of your decision. They may contact you with further instructions if necessary."
|
||||
msgstr "The document owner has been notified of your decision. They may contact you with further instructions if necessary."
|
||||
|
||||
#. placeholder {0}: data.delegatedOwnerName || data.delegatedOwnerEmail
|
||||
#. placeholder {1}: data.teamName
|
||||
#: packages/lib/utils/document-audit-logs.ts
|
||||
msgid "The document ownership was delegated to {0} on behalf of {1}"
|
||||
msgstr "The document ownership was delegated to {0} on behalf of {1}"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-use-dialog.tsx
|
||||
msgid "The document was created but could not be sent to recipients."
|
||||
msgstr "The document was created but could not be sent to recipients."
|
||||
@@ -8821,8 +8896,8 @@ msgid "The email domain you are looking for may have been removed, renamed or ma
|
||||
msgstr "The email domain you are looking for may have been removed, renamed or may have never existed."
|
||||
|
||||
#: apps/remix/app/components/forms/signin.tsx
|
||||
msgid "The email or password provided is incorrect"
|
||||
msgstr "The email or password provided is incorrect"
|
||||
msgid "The email or password provided is incorrect."
|
||||
msgstr "The email or password provided is incorrect."
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
@@ -9020,8 +9095,8 @@ msgid "The token you have used to reset your password is either expired or it ne
|
||||
msgstr "The token you have used to reset your password is either expired or it never existed. If you have still forgotten your password, please request a new reset link."
|
||||
|
||||
#: apps/remix/app/components/forms/signin.tsx
|
||||
msgid "The two-factor authentication code provided is incorrect"
|
||||
msgstr "The two-factor authentication code provided is incorrect"
|
||||
msgid "The two-factor authentication code provided is incorrect."
|
||||
msgstr "The two-factor authentication code provided is incorrect."
|
||||
|
||||
#: apps/remix/app/components/forms/editor/editor-field-signature-form.tsx
|
||||
msgid "The typed signature font size"
|
||||
@@ -9191,8 +9266,8 @@ msgid "This document was created using a direct link."
|
||||
msgstr "This document was created using a direct link."
|
||||
|
||||
#: packages/email/template-components/template-footer.tsx
|
||||
msgid "This document was sent using <0>Documenso.</0>"
|
||||
msgstr "This document was sent using <0>Documenso.</0>"
|
||||
msgid "This document was sent using <0>Documenso</0>."
|
||||
msgstr "This document was sent using <0>Documenso</0>."
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx
|
||||
msgid "This document will be duplicated."
|
||||
@@ -9523,6 +9598,10 @@ msgstr "Total Signers that Signed Up"
|
||||
msgid "Total Users"
|
||||
msgstr "Total Users"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
msgid "Transfer documents to a different team"
|
||||
msgstr "Transfer documents to a different team"
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
msgid "Triggers"
|
||||
@@ -9535,6 +9614,10 @@ msgstr "Triggers"
|
||||
msgid "Try again"
|
||||
msgstr "Try again"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Turn on AI detection to automatically find recipients and fields in your documents. AI providers do not retain your data for training."
|
||||
msgstr "Turn on AI detection to automatically find recipients and fields in your documents. AI providers do not retain your data for training."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx
|
||||
msgid "Two factor authentication"
|
||||
msgstr "Two factor authentication"
|
||||
@@ -9681,6 +9764,10 @@ msgstr "Unauthorized"
|
||||
msgid "Uncompleted"
|
||||
msgstr "Uncompleted"
|
||||
|
||||
#: packages/ui/primitives/signature-pad/signature-pad-draw.tsx
|
||||
msgid "Undo"
|
||||
msgstr "Undo"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx
|
||||
@@ -10293,8 +10380,8 @@ msgstr "Waiting for Your Turn"
|
||||
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx
|
||||
msgid "Want to send slick signing links like this one? <0>Check out Documenso.</0>"
|
||||
msgstr "Want to send slick signing links like this one? <0>Check out Documenso.</0>"
|
||||
msgid "Want to send slick signing links like this one? <0>Check out Documenso</0>."
|
||||
msgstr "Want to send slick signing links like this one? <0>Check out Documenso</0>."
|
||||
|
||||
#: apps/remix/app/routes/_profile+/_layout.tsx
|
||||
msgid "Want your own public profile?"
|
||||
@@ -10329,6 +10416,10 @@ msgstr "We are unable to update this passkey at the moment. Please try again lat
|
||||
msgid "We couldn't create a Stripe customer. Please try again."
|
||||
msgstr "We couldn't create a Stripe customer. Please try again."
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "We couldn't enable AI features right now. Please try again."
|
||||
msgstr "We couldn't enable AI features right now. Please try again."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx
|
||||
msgid "We couldn't update the group. Please try again."
|
||||
msgstr "We couldn't update the group. Please try again."
|
||||
@@ -10529,16 +10620,6 @@ msgstr "We encountered an unknown error while attempting update the team email.
|
||||
msgid "We encountered an unknown error while attempting update your profile. Please try again later."
|
||||
msgstr "We encountered an unknown error while attempting update your profile. Please try again later."
|
||||
|
||||
#. placeholder {0}: detectedFields.length
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "We found {0} field(s) in your document."
|
||||
msgstr "We found {0} field(s) in your document."
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "We found {0} recipient(s) in your document."
|
||||
msgstr "We found {0} recipient(s) in your document."
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-email-add-dialog.tsx
|
||||
msgid "We have sent a confirmation email for verification."
|
||||
msgstr "We have sent a confirmation email for verification."
|
||||
@@ -10788,6 +10869,7 @@ msgstr "Yearly"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Yes"
|
||||
|
||||
@@ -10900,13 +10982,13 @@ msgid "You are currently updating <0>{0}</0>"
|
||||
msgstr "You are currently updating <0>{0}</0>"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-member-update-dialog.tsx
|
||||
msgid "You are currently updating <0>{memberName}.</0>"
|
||||
msgstr "You are currently updating <0>{memberName}.</0>"
|
||||
msgid "You are currently updating <0>{memberName}</0>."
|
||||
msgstr "You are currently updating <0>{memberName}</0>."
|
||||
|
||||
#: apps/remix/app/components/dialogs/admin-organisation-member-update-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx
|
||||
msgid "You are currently updating <0>{organisationMemberName}.</0>"
|
||||
msgstr "You are currently updating <0>{organisationMemberName}.</0>"
|
||||
msgid "You are currently updating <0>{organisationMemberName}</0>."
|
||||
msgstr "You are currently updating <0>{organisationMemberName}</0>."
|
||||
|
||||
#: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
|
||||
msgid "You are currently updating the <0>{passkeyName}</0> passkey."
|
||||
@@ -10967,16 +11049,16 @@ msgstr "You can enable access to allow all organisation members to access this t
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.email.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.email.tsx
|
||||
msgid "You can manage your email preferences here"
|
||||
msgstr "You can manage your email preferences here"
|
||||
msgid "You can manage your email preferences here."
|
||||
msgstr "You can manage your email preferences here."
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx
|
||||
msgid "You can only detect fields in draft envelopes"
|
||||
msgstr "You can only detect fields in draft envelopes"
|
||||
|
||||
#: packages/email/templates/confirm-team-email.tsx
|
||||
msgid "You can revoke access at any time in your team settings on Documenso <0>here.</0>"
|
||||
msgstr "You can revoke access at any time in your team settings on Documenso <0>here.</0>"
|
||||
msgid "You can revoke access at any time in your team settings on Documenso <0>here</0>."
|
||||
msgstr "You can revoke access at any time in your team settings on Documenso <0>here</0>."
|
||||
|
||||
#: apps/remix/app/components/forms/public-profile-form.tsx
|
||||
msgid "You can update the profile URL by updating the team URL in the general settings page."
|
||||
@@ -11009,8 +11091,8 @@ msgid "You cannot delete a group which has a higher role than you."
|
||||
msgstr "You cannot delete a group which has a higher role than you."
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-item-delete-dialog.tsx
|
||||
msgid "You cannot delete this item because the document has been sent to recipients"
|
||||
msgstr "You cannot delete this item because the document has been sent to recipients"
|
||||
msgid "You cannot delete this item because the document has been sent to recipients."
|
||||
msgstr "You cannot delete this item because the document has been sent to recipients."
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-group-update-dialog.tsx
|
||||
msgid "You cannot modify a group which has a higher role than you."
|
||||
@@ -11036,8 +11118,8 @@ msgstr "You cannot upload documents at this time."
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-upload-button.tsx
|
||||
msgid "You cannot upload encrypted PDFs"
|
||||
msgstr "You cannot upload encrypted PDFs"
|
||||
msgid "You cannot upload encrypted PDFs."
|
||||
msgstr "You cannot upload encrypted PDFs."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.billing.tsx
|
||||
msgid "You currently have an inactive <0>{currentProductName}</0> subscription"
|
||||
@@ -11048,8 +11130,8 @@ msgid "You currently have no access to any teams within this organisation. Pleas
|
||||
msgstr "You currently have no access to any teams within this organisation. Please contact your organisation to request access."
|
||||
|
||||
#: apps/remix/app/components/forms/token.tsx
|
||||
msgid "You do not have permission to create a token for this team"
|
||||
msgstr "You do not have permission to create a token for this team"
|
||||
msgid "You do not have permission to create a token for this team."
|
||||
msgstr "You do not have permission to create a token for this team."
|
||||
|
||||
#: apps/remix/app/components/tables/user-billing-organisations-table.tsx
|
||||
msgid "You don't manage billing for any organisations."
|
||||
@@ -11118,8 +11200,8 @@ msgstr "You have not yet created or received any documents. To create a document
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-upload-button.tsx
|
||||
msgid "You have reached the limit of the number of files per envelope"
|
||||
msgstr "You have reached the limit of the number of files per envelope"
|
||||
msgid "You have reached the limit of the number of files per envelope."
|
||||
msgstr "You have reached the limit of the number of files per envelope."
|
||||
|
||||
#. placeholder {0}: quota.directTemplates
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
@@ -11274,6 +11356,10 @@ msgstr "You will now be required to enter a code from your authenticator app whe
|
||||
msgid "You will receive an email copy of the signed document once everyone has signed."
|
||||
msgstr "You will receive an email copy of the signed document once everyone has signed."
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "You're an admin. You can enable AI features for this team right away. Everyone on the team will see AI detection once enabled."
|
||||
msgstr "You're an admin. You can enable AI features for this team right away. Everyone on the team will see AI detection once enabled."
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "You've made too many detection requests. Please wait a minute before trying again."
|
||||
@@ -11332,6 +11418,10 @@ msgstr "Your current plan is past due."
|
||||
msgid "Your direct signing templates"
|
||||
msgstr "Your direct signing templates"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Your document content will be sent securely to our AI provider solely for detection and will not be stored or used for training."
|
||||
msgstr "Your document content will be sent securely to our AI provider solely for detection and will not be stored or used for training."
|
||||
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-upload.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Your document failed to upload."
|
||||
@@ -11367,7 +11457,7 @@ msgstr "Your document has been successfully duplicated."
|
||||
msgid "Your document has been uploaded successfully."
|
||||
msgstr "Your document has been uploaded successfully."
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
msgstr "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
|
||||
|
||||
+267
-177
File diff suppressed because it is too large
Load Diff
+267
-177
File diff suppressed because it is too large
Load Diff
+267
-177
File diff suppressed because it is too large
Load Diff
+263
-173
File diff suppressed because it is too large
Load Diff
+264
-174
File diff suppressed because it is too large
Load Diff
+265
-175
File diff suppressed because it is too large
Load Diff
+262
-172
File diff suppressed because it is too large
Load Diff
@@ -96,6 +96,11 @@ msgstr "{0, plural, one {# campo} other {# campos}}"
|
||||
msgid "{0, plural, one {# folder} other {# folders}}"
|
||||
msgstr "{0, plural, one {# pasta} other {# pastas}}"
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0, plural, one {# recipient have been added from AI detection.} other {# recipients have been added from AI detection.}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: template.recipients.length
|
||||
#: apps/remix/app/routes/_recipient+/d.$token+/_index.tsx
|
||||
msgid "{0, plural, one {# recipient} other {# recipients}}"
|
||||
@@ -146,11 +151,44 @@ msgstr "{0, plural, one {1 campo correspondente} other {# campos correspondentes
|
||||
msgid "{0, plural, one {1 Recipient} other {# Recipients}}"
|
||||
msgstr "{0, plural, one {1 Destinatário} other {# Destinatários}}"
|
||||
|
||||
#. placeholder {0}: progress.fieldsDetected
|
||||
#. placeholder {1}: progress.pagesProcessed
|
||||
#. placeholder {2}: progress.totalPages
|
||||
#. placeholder {3}: progress.pagesProcessed
|
||||
#. placeholder {4}: progress.totalPages
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "{0, plural, one {Page {1} of {2} - # field found} other {Page {3} of {4} - # fields found}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: progress.recipientsDetected
|
||||
#. placeholder {1}: progress.pagesProcessed
|
||||
#. placeholder {2}: progress.totalPages
|
||||
#. placeholder {3}: progress.pagesProcessed
|
||||
#. placeholder {4}: progress.totalPages
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "{0, plural, one {Page {1} of {2} - # recipient found} other {Page {3} of {4} - # recipients found}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0, plural, one {Recipient added} other {Recipients added}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: pendingRecipients.length
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx
|
||||
msgid "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
||||
msgstr "{0, plural, one {Aguardando 1 destinatário} other {Aguardando # destinatários}}"
|
||||
|
||||
#. placeholder {0}: detectedFields.length
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "{0, plural, one {We found # field in your document.} other {We found # fields in your document.}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "{0, plural, one {We found # recipient in your document.} other {We found # recipients in your document.}}"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: _(FRIENDLY_FIELD_TYPE[fieldType as FieldType])
|
||||
#. placeholder {0}: route.label
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx
|
||||
@@ -195,11 +233,6 @@ msgstr "{0} de {1} documentos restantes este mês."
|
||||
msgid "{0} on behalf of \"{1}\" has invited you to {recipientActionVerb} the document \"{2}\"."
|
||||
msgstr "{0} em nome de \"{1}\" convidou você para {recipientActionVerb} o documento \"{2}\"."
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "{0} recipient(s) have been added from AI detection."
|
||||
msgstr "{0} destinatário(s) foram adicionados pela detecção de IA."
|
||||
|
||||
#. placeholder {0}: organisation.name
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "{0} Teams"
|
||||
@@ -846,9 +879,6 @@ msgid "A request to use your email has been initiated by {0} on Documenso"
|
||||
msgstr "Uma solicitação para usar seu e-mail foi iniciada por {0} no Documenso"
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
msgid "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso"
|
||||
msgstr "Um segredo que será enviado para sua URL para que você possa verificar se a solicitação foi enviada pelo Documenso"
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
msgid "A secret that will be sent to your URL so you can verify that the request has been sent by Documenso."
|
||||
msgstr "Um segredo que será enviado para sua URL para que você possa verificar se a solicitação foi enviada pelo Documenso."
|
||||
@@ -1283,6 +1313,10 @@ msgstr "Após o envio, um documento será gerado automaticamente e adicionado à
|
||||
msgid "AI Features"
|
||||
msgstr "Recursos de IA"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/document/document-status.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx
|
||||
msgid "All"
|
||||
@@ -2260,6 +2294,10 @@ msgstr "Gráficos"
|
||||
msgid "Checkbox"
|
||||
msgstr "Caixa de seleção"
|
||||
|
||||
#: packages/ui/primitives/document-flow/field-content.tsx
|
||||
msgid "Checkbox option"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx
|
||||
msgid "Checkbox Settings"
|
||||
msgstr "Configurações da Caixa de Seleção"
|
||||
@@ -2363,6 +2401,7 @@ msgstr "Segredo do Cliente"
|
||||
msgid "Client secret is required"
|
||||
msgstr "Segredo do Cliente é obrigatório"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
@@ -2375,7 +2414,6 @@ msgstr "Segredo do Cliente é obrigatório"
|
||||
#: apps/remix/app/components/dialogs/team-group-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-group-update-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-member-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-use-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-test-dialog.tsx
|
||||
@@ -2386,7 +2424,9 @@ msgstr "Segredo do Cliente é obrigatório"
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auth-2fa.tsx
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-auth-passkey.tsx
|
||||
#: apps/remix/app/components/general/document/document-recipient-link-copy-dialog.tsx
|
||||
#: packages/ui/primitives/dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx
|
||||
#: packages/ui/primitives/sheet.tsx
|
||||
msgid "Close"
|
||||
msgstr "Fechar"
|
||||
|
||||
@@ -3064,6 +3104,10 @@ msgstr "Fuso Horário Padrão"
|
||||
msgid "Default Value"
|
||||
msgstr "Valor Padrão"
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Delegate Document Ownership"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/document-delete-dialog.tsx
|
||||
msgid "delete"
|
||||
msgstr "excluir"
|
||||
@@ -3283,8 +3327,8 @@ msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
#: packages/email/templates/reset-password.tsx
|
||||
msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us.</0>"
|
||||
msgstr "Não solicitou uma alteração de senha? Estamos aqui para ajudá-lo a proteger sua conta, basta <0>entrar em contato conosco.</0>"
|
||||
msgid "Didn't request a password change? We are here to help you secure your account, just <0>contact us</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/template/template-direct-link-badge.tsx
|
||||
#: apps/remix/app/components/tables/templates-table.tsx
|
||||
@@ -3627,6 +3671,11 @@ msgctxt "Audit log format"
|
||||
msgid "Document opened"
|
||||
msgstr "Documento aberto"
|
||||
|
||||
#: packages/lib/utils/document-audit-logs.ts
|
||||
msgctxt "Audit log format"
|
||||
msgid "Document ownership delegated"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/document/document-status.tsx
|
||||
msgid "Document pending"
|
||||
msgstr "Documento pendente"
|
||||
@@ -3825,6 +3874,11 @@ msgstr "Nome do Domínio"
|
||||
msgid "Don't have an account? <0>Sign up</0>"
|
||||
msgstr "Não tem uma conta? <0>Inscreva-se</0>"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
msgid "Don't transfer (Delete all documents)"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx
|
||||
#: apps/remix/app/components/forms/2fa/view-recovery-codes-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-certificate-qr-view.tsx
|
||||
@@ -3963,6 +4017,7 @@ msgstr "Ex: 100"
|
||||
#: apps/remix/app/components/general/document/document-page-view-button.tsx
|
||||
#: apps/remix/app/components/general/document/document-page-view-dropdown.tsx
|
||||
#: apps/remix/app/components/general/teams/team-email-dropdown.tsx
|
||||
#: apps/remix/app/components/tables/admin-dashboard-users-table.tsx
|
||||
#: apps/remix/app/components/tables/documents-table-action-button.tsx
|
||||
#: apps/remix/app/components/tables/documents-table-action-dropdown.tsx
|
||||
#: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
|
||||
@@ -4179,6 +4234,15 @@ msgstr "Ativar conta"
|
||||
msgid "Enable Account"
|
||||
msgstr "Ativar Conta"
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "Enable AI detection"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Enable AI features"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Enable AI-powered features such as automatic recipient detection. When enabled, document content will be sent to AI providers. We only use providers that do not retain data for training and prefer European regions where available."
|
||||
msgstr "Ative recursos com tecnologia de IA, como detecção automática de destinatários. Quando ativado, o conteúdo do documento será enviado para provedores de IA. Usamos apenas provedores que não retêm dados para treinamento e preferimos regiões europeias quando disponíveis."
|
||||
@@ -4219,6 +4283,10 @@ msgstr "Ativar ordem de assinatura"
|
||||
msgid "Enable SSO portal"
|
||||
msgstr "Ativar portal SSO"
|
||||
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Enable team API tokens to delegate document ownership to another team member."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
@@ -4817,10 +4885,26 @@ msgstr "Ir para o início"
|
||||
msgid "Go to document"
|
||||
msgstr "Ir para o documento"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to first page"
|
||||
msgstr ""
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to last page"
|
||||
msgstr ""
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/documents.$id.tsx
|
||||
msgid "Go to owner"
|
||||
msgstr "Ir para o proprietário"
|
||||
|
||||
#: packages/ui/primitives/data-table-pagination.tsx
|
||||
msgid "Go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Go to team"
|
||||
msgstr "Ir para a equipe"
|
||||
@@ -4901,8 +4985,8 @@ msgid "Here you can set branding preferences for your organisation. Teams will i
|
||||
msgstr "Aqui você pode definir preferências de marca para sua organização. As equipes herdarão essas configurações por padrão."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx
|
||||
msgid "Here you can set branding preferences for your team"
|
||||
msgstr "Aqui você pode definir preferências de marca para sua equipe"
|
||||
msgid "Here you can set branding preferences for your team."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.document.tsx
|
||||
msgid "Here you can set document preferences for your organisation. Teams will inherit these settings by default."
|
||||
@@ -4917,12 +5001,12 @@ msgid "Here you can set preferences and defaults for your team."
|
||||
msgstr "Aqui você pode definir preferências e padrões para sua equipe."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx
|
||||
msgid "Here you can set your general branding preferences"
|
||||
msgstr "Aqui você pode definir suas preferências gerais de marca"
|
||||
msgid "Here you can set your general branding preferences."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.document.tsx
|
||||
msgid "Here you can set your general document preferences"
|
||||
msgstr "Aqui você pode definir suas preferências gerais de documento"
|
||||
msgid "Here you can set your general document preferences."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
msgid "Here's how it works:"
|
||||
@@ -5087,6 +5171,7 @@ msgstr "Herdar método de autenticação"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/email-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/email-preferences-form.tsx
|
||||
msgid "Inherit from organisation"
|
||||
@@ -5479,6 +5564,7 @@ msgid "Looking for signature fields"
|
||||
msgstr "Procurando campos de assinatura"
|
||||
|
||||
#: apps/remix/app/components/tables/admin-organisations-table.tsx
|
||||
#: apps/remix/app/components/tables/organisation-groups-table.tsx
|
||||
#: apps/remix/app/components/tables/organisation-teams-table.tsx
|
||||
#: apps/remix/app/components/tables/user-organisations-table.tsx
|
||||
msgid "Manage"
|
||||
@@ -5539,6 +5625,10 @@ msgstr "Gerenciar contas vinculadas"
|
||||
msgid "Manage organisation"
|
||||
msgstr "Gerenciar organização"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Manage Organisation"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx
|
||||
msgid "Manage organisations"
|
||||
msgstr "Gerenciar organizações"
|
||||
@@ -5702,15 +5792,15 @@ msgstr "Membro Desde"
|
||||
msgid "Members"
|
||||
msgstr "Membros"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/forms/support-ticket-form.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Message"
|
||||
msgstr "Mensagem"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Message <0>(Optional)</0>"
|
||||
msgstr "Mensagem <0>(Opcional)</0>"
|
||||
|
||||
@@ -5860,10 +5950,6 @@ msgstr "Nunca expirar"
|
||||
msgid "New Password"
|
||||
msgstr "Nova Senha"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "New Template"
|
||||
msgstr "Novo Modelo"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-group-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-member-create-dialog.tsx
|
||||
#: apps/remix/app/components/embed/embed-direct-template-client-page.tsx
|
||||
@@ -5889,6 +5975,7 @@ msgstr "Nome do Próximo Destinatário"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "No"
|
||||
msgstr "Não"
|
||||
|
||||
@@ -6096,8 +6183,8 @@ msgid "Once you have scanned the QR code or entered the code manually, enter the
|
||||
msgstr "Depois de escanear o código QR ou inserir o código manualmente, insira o código fornecido pelo seu aplicativo autenticador abaixo."
|
||||
|
||||
#: apps/remix/app/components/dialogs/organisation-email-domain-records-dialog.tsx
|
||||
msgid "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button"
|
||||
msgstr "Depois de atualizar seus registros DNS, pode levar até 48 horas para que eles sejam propagados. Assim que a propagação do DNS estiver concluída, você precisará voltar e pressionar o botão \"Sincronizar\" domínios"
|
||||
msgid "Once you update your DNS records, it may take up to 48 hours for it to be propogated. Once the DNS propagation is complete you will need to come back and press the \"Sync\" domains button."
|
||||
msgstr ""
|
||||
|
||||
#: packages/lib/constants/template.ts
|
||||
msgid "Once your template is set up, share the link anywhere you want. The person who opens the link will be able to enter their information in the direct link recipient field and complete any other fields assigned to them."
|
||||
@@ -6131,6 +6218,10 @@ msgstr "Apenas arquivos PDF são permitidos"
|
||||
msgid "Oops! Something went wrong."
|
||||
msgstr "Ops! Algo deu errado."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx
|
||||
msgid "Open menu"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/stack-avatars-with-tooltip.tsx
|
||||
msgid "Opened"
|
||||
msgstr "Aberto"
|
||||
@@ -6324,20 +6415,6 @@ msgstr "Propriedade transferida para {organisationMemberName}."
|
||||
msgid "Page {0} of {1}"
|
||||
msgstr "Página {0} de {1}"
|
||||
|
||||
#. placeholder {0}: progress.pagesProcessed
|
||||
#. placeholder {1}: progress.totalPages
|
||||
#. placeholder {2}: progress.fieldsDetected
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "Page {0} of {1} - {2} field(s) found"
|
||||
msgstr "Página {0} de {1} - {2} campo(s) encontrado(s)"
|
||||
|
||||
#. placeholder {0}: progress.pagesProcessed
|
||||
#. placeholder {1}: progress.totalPages
|
||||
#. placeholder {2}: progress.recipientsDetected
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "Page {0} of {1} - {2} recipient(s) found"
|
||||
msgstr "Página {0} de {1} - {2} destinatário(s) encontrado(s)"
|
||||
|
||||
#. placeholder {0}: i + 1
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/primitives/pdf-viewer/base.tsx
|
||||
@@ -6683,10 +6760,6 @@ msgstr "Por favor, tente um domínio diferente."
|
||||
msgid "Please try again and make sure you enter the correct email address."
|
||||
msgstr "Por favor, tente novamente e certifique-se de inserir o endereço de e-mail correto."
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "Please try again later."
|
||||
msgstr "Por favor, tente novamente mais tarde."
|
||||
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/components/pdf-viewer/pdf-viewer-konva.tsx
|
||||
#: packages/ui/primitives/pdf-viewer/base.tsx
|
||||
@@ -6964,10 +7037,6 @@ msgstr "Destinatário atualizado"
|
||||
msgid "Recipients"
|
||||
msgstr "Destinatários"
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx
|
||||
msgid "Recipients added"
|
||||
msgstr "Destinatários adicionados"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/admin+/stats.tsx
|
||||
msgid "Recipients metrics"
|
||||
msgstr "Métricas de destinatários"
|
||||
@@ -7141,8 +7210,8 @@ msgstr "Responder ao e-mail"
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Reply To Email"
|
||||
msgstr "Responder Para E-mail"
|
||||
msgid "Reply To Email <0>(Optional)</0>"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/webhook-logs-sheet.tsx
|
||||
msgid "Request"
|
||||
@@ -7279,6 +7348,11 @@ msgstr "Tentar novamente"
|
||||
msgid "Return"
|
||||
msgstr "Retornar"
|
||||
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/rejected.tsx
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/waiting.tsx
|
||||
msgid "Return Home"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx
|
||||
msgid "Return to Documenso sign in page here"
|
||||
msgstr "Retornar para a página de login do Documenso aqui"
|
||||
@@ -7445,6 +7519,7 @@ msgid "See the background jobs tab for the status"
|
||||
msgstr "Veja a aba de trabalhos em segundo plano para o status"
|
||||
|
||||
#: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx
|
||||
#: packages/ui/primitives/document-flow/field-content.tsx
|
||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx
|
||||
#: packages/ui/primitives/document-flow/types.ts
|
||||
msgid "Select"
|
||||
@@ -8084,7 +8159,6 @@ msgstr "Alguns signatários não receberam um campo de assinatura. Por favor, at
|
||||
#: apps/remix/app/components/dialogs/team-email-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-inherit-member-disable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/team-inherit-member-enable-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-delete-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
@@ -8247,14 +8321,14 @@ msgstr "Cliente Stripe criado com sucesso"
|
||||
msgid "Stripe Customer ID"
|
||||
msgstr "ID do Cliente Stripe"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/forms/support-ticket-form.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
msgid "Subject"
|
||||
msgstr "Assunto"
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-advanced-settings.tsx
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx
|
||||
#: packages/ui/primitives/document-flow/add-subject.tsx
|
||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx
|
||||
msgid "Subject <0>(Optional)</0>"
|
||||
msgstr "Assunto <0>(Opcional)</0>"
|
||||
@@ -8575,7 +8649,6 @@ msgstr "Equipes às quais este grupo da organização está atualmente atribuíd
|
||||
msgid "Template"
|
||||
msgstr "Modelo"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: packages/ui/primitives/document-upload-button.tsx
|
||||
msgid "Template (Legacy)"
|
||||
msgstr "Modelo (Legado)"
|
||||
@@ -8588,7 +8661,7 @@ msgstr "Modelo Criado"
|
||||
msgid "Template deleted"
|
||||
msgstr "Modelo excluído"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Template document uploaded"
|
||||
msgstr "Documento de modelo enviado"
|
||||
|
||||
@@ -8650,10 +8723,6 @@ msgstr "Modelo enviado"
|
||||
msgid "Templates"
|
||||
msgstr "Modelos"
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
msgid "Templates allow you to quickly generate documents with pre-filled recipients and fields."
|
||||
msgstr "Modelos permitem gerar documentos rapidamente com destinatários e campos pré-preenchidos."
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx
|
||||
msgid "Test"
|
||||
msgstr "Teste"
|
||||
@@ -8787,6 +8856,12 @@ msgstr "O proprietário do documento foi notificado sobre esta rejeição. Nenhu
|
||||
msgid "The document owner has been notified of your decision. They may contact you with further instructions if necessary."
|
||||
msgstr "O proprietário do documento foi notificado sobre sua decisão. Eles podem entrar em contato com você com mais instruções, se necessário."
|
||||
|
||||
#. placeholder {0}: data.delegatedOwnerName || data.delegatedOwnerEmail
|
||||
#. placeholder {1}: data.teamName
|
||||
#: packages/lib/utils/document-audit-logs.ts
|
||||
msgid "The document ownership was delegated to {0} on behalf of {1}"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-use-dialog.tsx
|
||||
msgid "The document was created but could not be sent to recipients."
|
||||
msgstr "O documento foi criado, mas não pôde ser enviado aos destinatários."
|
||||
@@ -8821,8 +8896,8 @@ msgid "The email domain you are looking for may have been removed, renamed or ma
|
||||
msgstr "O domínio de e-mail que você está procurando pode ter sido removido, renomeado ou nunca ter existido."
|
||||
|
||||
#: apps/remix/app/components/forms/signin.tsx
|
||||
msgid "The email or password provided is incorrect"
|
||||
msgstr "O e-mail ou senha fornecidos estão incorretos"
|
||||
msgid "The email or password provided is incorrect."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
@@ -9020,8 +9095,8 @@ msgid "The token you have used to reset your password is either expired or it ne
|
||||
msgstr "O token que você usou para redefinir sua senha expirou ou nunca existiu. Se você ainda esqueceu sua senha, solicite um novo link de redefinição."
|
||||
|
||||
#: apps/remix/app/components/forms/signin.tsx
|
||||
msgid "The two-factor authentication code provided is incorrect"
|
||||
msgstr "O código de autenticação de dois fatores fornecido está incorreto"
|
||||
msgid "The two-factor authentication code provided is incorrect."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/forms/editor/editor-field-signature-form.tsx
|
||||
msgid "The typed signature font size"
|
||||
@@ -9099,7 +9174,6 @@ msgstr "Esta conta foi desativada. Entre em contato com o suporte."
|
||||
#: apps/remix/app/components/forms/signin.tsx
|
||||
msgid "This account has not been verified. Please verify your account before signing in."
|
||||
msgstr "Esta conta não foi verificada. Verifique sua conta antes de entrar."
|
||||
msgstr "Esta conta não foi verificada. Verifique sua conta antes de entrar."
|
||||
|
||||
#: apps/remix/app/components/dialogs/admin-user-reset-two-factor-dialog.tsx
|
||||
msgid "This action is irreversible. Please ensure you have informed the user before proceeding."
|
||||
@@ -9192,8 +9266,8 @@ msgid "This document was created using a direct link."
|
||||
msgstr "Este documento foi criado usando um link direto."
|
||||
|
||||
#: packages/email/template-components/template-footer.tsx
|
||||
msgid "This document was sent using <0>Documenso.</0>"
|
||||
msgstr "Este documento foi enviado usando <0>Documenso.</0>"
|
||||
msgid "This document was sent using <0>Documenso</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-duplicate-dialog.tsx
|
||||
msgid "This document will be duplicated."
|
||||
@@ -9524,6 +9598,10 @@ msgstr "Total de Signatários que se Inscreveram"
|
||||
msgid "Total Users"
|
||||
msgstr "Total de Usuários"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-delete-dialog.tsx
|
||||
msgid "Transfer documents to a different team"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/webhook-create-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/webhook-edit-dialog.tsx
|
||||
msgid "Triggers"
|
||||
@@ -9536,6 +9614,10 @@ msgstr "Gatilhos"
|
||||
msgid "Try again"
|
||||
msgstr "Tente novamente"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Turn on AI detection to automatically find recipients and fields in your documents. AI providers do not retain your data for training."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx
|
||||
msgid "Two factor authentication"
|
||||
msgstr "Autenticação de dois fatores"
|
||||
@@ -9682,6 +9764,10 @@ msgstr "Não autorizado"
|
||||
msgid "Uncompleted"
|
||||
msgstr "Não concluído"
|
||||
|
||||
#: packages/ui/primitives/signature-pad/signature-pad-draw.tsx
|
||||
msgid "Undo"
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx
|
||||
@@ -10294,8 +10380,8 @@ msgstr "Aguardando Sua Vez"
|
||||
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx
|
||||
#: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx
|
||||
msgid "Want to send slick signing links like this one? <0>Check out Documenso.</0>"
|
||||
msgstr "Quer enviar links de assinatura elegantes como este? <0>Confira o Documenso.</0>"
|
||||
msgid "Want to send slick signing links like this one? <0>Check out Documenso</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_profile+/_layout.tsx
|
||||
msgid "Want your own public profile?"
|
||||
@@ -10330,6 +10416,10 @@ msgstr "Não conseguimos atualizar esta passkey no momento. Por favor, tente nov
|
||||
msgid "We couldn't create a Stripe customer. Please try again."
|
||||
msgstr "Não conseguimos criar um cliente Stripe. Por favor, tente novamente."
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "We couldn't enable AI features right now. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx
|
||||
msgid "We couldn't update the group. Please try again."
|
||||
msgstr "Não conseguimos atualizar o grupo. Por favor, tente novamente."
|
||||
@@ -10530,16 +10620,6 @@ msgstr "Encontramos um erro desconhecido ao tentar atualizar o e-mail da equipe.
|
||||
msgid "We encountered an unknown error while attempting update your profile. Please try again later."
|
||||
msgstr "Encontramos um erro desconhecido ao tentar atualizar seu perfil. Por favor, tente novamente mais tarde."
|
||||
|
||||
#. placeholder {0}: detectedFields.length
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
msgid "We found {0} field(s) in your document."
|
||||
msgstr "Encontramos {0} campo(s) no seu documento."
|
||||
|
||||
#. placeholder {0}: detectedRecipients.length
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "We found {0} recipient(s) in your document."
|
||||
msgstr "Encontramos {0} destinatário(s) no seu documento."
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-email-add-dialog.tsx
|
||||
msgid "We have sent a confirmation email for verification."
|
||||
msgstr "Enviamos um e-mail de confirmação para verificação."
|
||||
@@ -10789,6 +10869,7 @@ msgstr "Anual"
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
#: apps/remix/app/components/forms/document-preferences-form.tsx
|
||||
msgid "Yes"
|
||||
msgstr "Sim"
|
||||
|
||||
@@ -10901,13 +10982,13 @@ msgid "You are currently updating <0>{0}</0>"
|
||||
msgstr "Você está atualizando <0>{0}</0>"
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-member-update-dialog.tsx
|
||||
msgid "You are currently updating <0>{memberName}.</0>"
|
||||
msgstr "Você está atualizando <0>{memberName}.</0>"
|
||||
msgid "You are currently updating <0>{memberName}</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/admin-organisation-member-update-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx
|
||||
msgid "You are currently updating <0>{organisationMemberName}.</0>"
|
||||
msgstr "Você está atualizando <0>{organisationMemberName}.</0>"
|
||||
msgid "You are currently updating <0>{organisationMemberName}</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx
|
||||
msgid "You are currently updating the <0>{passkeyName}</0> passkey."
|
||||
@@ -10968,16 +11049,16 @@ msgstr "Você pode ativar o acesso para permitir que todos os membros da organiz
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.email.tsx
|
||||
#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.email.tsx
|
||||
msgid "You can manage your email preferences here"
|
||||
msgstr "Você pode gerenciar suas preferências de e-mail aqui"
|
||||
msgid "You can manage your email preferences here."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page.tsx
|
||||
msgid "You can only detect fields in draft envelopes"
|
||||
msgstr "Você só pode detectar campos em envelopes de rascunho"
|
||||
|
||||
#: packages/email/templates/confirm-team-email.tsx
|
||||
msgid "You can revoke access at any time in your team settings on Documenso <0>here.</0>"
|
||||
msgstr "Você pode revogar o acesso a qualquer momento nas configurações da sua equipe no Documenso <0>aqui.</0>"
|
||||
msgid "You can revoke access at any time in your team settings on Documenso <0>here</0>."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/forms/public-profile-form.tsx
|
||||
msgid "You can update the profile URL by updating the team URL in the general settings page."
|
||||
@@ -11010,8 +11091,8 @@ msgid "You cannot delete a group which has a higher role than you."
|
||||
msgstr "Você não pode excluir um grupo que tem uma função superior à sua."
|
||||
|
||||
#: apps/remix/app/components/dialogs/envelope-item-delete-dialog.tsx
|
||||
msgid "You cannot delete this item because the document has been sent to recipients"
|
||||
msgstr "Você não pode excluir este item porque o documento foi enviado aos destinatários"
|
||||
msgid "You cannot delete this item because the document has been sent to recipients."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/team-group-update-dialog.tsx
|
||||
msgid "You cannot modify a group which has a higher role than you."
|
||||
@@ -11037,8 +11118,8 @@ msgstr "Você não pode enviar documentos neste momento."
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-upload-button.tsx
|
||||
msgid "You cannot upload encrypted PDFs"
|
||||
msgstr "Você não pode enviar PDFs criptografados"
|
||||
msgid "You cannot upload encrypted PDFs."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.billing.tsx
|
||||
msgid "You currently have an inactive <0>{currentProductName}</0> subscription"
|
||||
@@ -11049,8 +11130,8 @@ msgid "You currently have no access to any teams within this organisation. Pleas
|
||||
msgstr "Você atualmente não tem acesso a nenhuma equipe dentro desta organização. Por favor, entre em contato com sua organização para solicitar acesso."
|
||||
|
||||
#: apps/remix/app/components/forms/token.tsx
|
||||
msgid "You do not have permission to create a token for this team"
|
||||
msgstr "Você não tem permissão para criar um token para esta equipe"
|
||||
msgid "You do not have permission to create a token for this team."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/tables/user-billing-organisations-table.tsx
|
||||
msgid "You don't manage billing for any organisations."
|
||||
@@ -11119,8 +11200,8 @@ msgstr "Você ainda não criou ou recebeu nenhum documento. Para criar um docume
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx
|
||||
#: apps/remix/app/components/general/envelope/envelope-upload-button.tsx
|
||||
msgid "You have reached the limit of the number of files per envelope"
|
||||
msgstr "Você atingiu o limite do número de arquivos por envelope"
|
||||
msgid "You have reached the limit of the number of files per envelope."
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: quota.directTemplates
|
||||
#: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx
|
||||
@@ -11275,6 +11356,10 @@ msgstr "Agora será necessário inserir um código do seu aplicativo autenticado
|
||||
msgid "You will receive an email copy of the signed document once everyone has signed."
|
||||
msgstr "Você receberá uma cópia por e-mail do documento assinado assim que todos assinarem."
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "You're an admin. You can enable AI features for this team right away. Everyone on the team will see AI detection once enabled."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx
|
||||
#: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx
|
||||
msgid "You've made too many detection requests. Please wait a minute before trying again."
|
||||
@@ -11333,6 +11418,10 @@ msgstr "Seu plano atual está vencido."
|
||||
msgid "Your direct signing templates"
|
||||
msgstr "Seus modelos de assinatura direta"
|
||||
|
||||
#: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx
|
||||
msgid "Your document content will be sent securely to our AI provider solely for detection and will not be stored or used for training."
|
||||
msgstr ""
|
||||
|
||||
#: apps/remix/app/components/embed/authoring/configure-document-upload.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Your document failed to upload."
|
||||
@@ -11368,7 +11457,7 @@ msgstr "Seu documento foi duplicado com sucesso."
|
||||
msgid "Your document has been uploaded successfully."
|
||||
msgstr "Seu documento foi enviado com sucesso."
|
||||
|
||||
#: apps/remix/app/components/dialogs/template-create-dialog.tsx
|
||||
#: apps/remix/app/components/general/document/document-upload-button-legacy.tsx
|
||||
msgid "Your document has been uploaded successfully. You will be redirected to the template page."
|
||||
msgstr "Seu documento foi enviado com sucesso. Você será redirecionado para a página do modelo."
|
||||
|
||||
@@ -11559,4 +11648,4 @@ msgstr "Seu código de verificação:"
|
||||
|
||||
#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx
|
||||
msgid "your-domain.com another-domain.com"
|
||||
msgstr "seu-dominio.com outro-dominio.com"
|
||||
msgstr "seu-dominio.com outro-dominio.com"
|
||||
|
||||
+267
-177
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,7 @@ export const ZDocumentAuditLogTypeSchema = z.enum([
|
||||
'DOCUMENT_TITLE_UPDATED', // When the document title is updated.
|
||||
'DOCUMENT_EXTERNAL_ID_UPDATED', // When the document external ID is updated.
|
||||
'DOCUMENT_MOVED_TO_TEAM', // When the document is moved to a team.
|
||||
'DOCUMENT_DELEGATED_OWNER_CREATED', // When the document delegated owner is created.
|
||||
|
||||
// ACCESS AUTH 2FA events.
|
||||
'DOCUMENT_ACCESS_AUTH_2FA_REQUESTED', // When ACCESS AUTH 2FA is requested.
|
||||
@@ -681,6 +682,18 @@ export const ZDocumentAuditLogEventDocumentMovedToTeamSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Document delegated owner created.
|
||||
*/
|
||||
export const ZDocumentAuditLogEventDocumentDelegatedOwnerCreatedSchema = z.object({
|
||||
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_DELEGATED_OWNER_CREATED),
|
||||
data: z.object({
|
||||
delegatedOwnerName: z.string().nullable(),
|
||||
delegatedOwnerEmail: z.string(),
|
||||
teamName: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ZDocumentAuditLogBaseSchema = z.object({
|
||||
id: z.string(),
|
||||
createdAt: z.date(),
|
||||
@@ -701,6 +714,7 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
|
||||
ZDocumentAuditLogEventDocumentCreatedSchema,
|
||||
ZDocumentAuditLogEventDocumentDeletedSchema,
|
||||
ZDocumentAuditLogEventDocumentMovedToTeamSchema,
|
||||
ZDocumentAuditLogEventDocumentDelegatedOwnerCreatedSchema,
|
||||
ZDocumentAuditLogEventDocumentFieldsAutoInsertedSchema,
|
||||
ZDocumentAuditLogEventDocumentFieldInsertedSchema,
|
||||
ZDocumentAuditLogEventDocumentFieldUninsertedSchema,
|
||||
|
||||
@@ -115,5 +115,40 @@ export type TEnvelopeLite = z.infer<typeof ZEnvelopeLiteSchema>;
|
||||
/**
|
||||
* A version of the envelope response schema when returning multiple envelopes at once from a single API endpoint.
|
||||
*/
|
||||
// export const ZEnvelopeManySchema = X
|
||||
// export type TEnvelopeMany = z.infer<typeof ZEnvelopeManySchema>;
|
||||
export const ZEnvelopeManySchema = EnvelopeSchema.pick({
|
||||
internalVersion: true,
|
||||
type: true,
|
||||
status: true,
|
||||
source: true,
|
||||
visibility: true,
|
||||
templateType: true,
|
||||
id: true,
|
||||
secondaryId: true,
|
||||
externalId: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
completedAt: true,
|
||||
deletedAt: true,
|
||||
title: true,
|
||||
authOptions: true,
|
||||
formValues: true,
|
||||
publicTitle: true,
|
||||
publicDescription: true,
|
||||
userId: true,
|
||||
teamId: true,
|
||||
folderId: true,
|
||||
templateId: true,
|
||||
}).extend({
|
||||
user: z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
}),
|
||||
recipients: ZEnvelopeRecipientLiteSchema.array(),
|
||||
team: TeamSchema.pick({
|
||||
id: true,
|
||||
url: true,
|
||||
}).nullable(),
|
||||
});
|
||||
|
||||
export type TEnvelopeMany = z.infer<typeof ZEnvelopeManySchema>;
|
||||
|
||||
@@ -31,7 +31,7 @@ export const ZClaimFlagsSchema = z.object({
|
||||
|
||||
authenticationPortal: z.boolean().optional(),
|
||||
|
||||
allowEnvelopes: z.boolean().optional(),
|
||||
allowLegacyEnvelopes: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export type TClaimFlags = z.infer<typeof ZClaimFlagsSchema>;
|
||||
@@ -84,9 +84,9 @@ export const SUBSCRIPTION_CLAIM_FEATURE_FLAGS: Record<
|
||||
key: 'authenticationPortal',
|
||||
label: 'Authentication portal',
|
||||
},
|
||||
allowEnvelopes: {
|
||||
key: 'allowEnvelopes',
|
||||
label: 'Allow envelopes',
|
||||
allowLegacyEnvelopes: {
|
||||
key: 'allowLegacyEnvelopes',
|
||||
label: 'Allow Legacy Envelopes',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -530,6 +530,13 @@ export const formatDocumentAuditLogAction = (
|
||||
anonymous: msg`Envelope item deleted`,
|
||||
identified: msg`${prefix} deleted an envelope item with title ${data.envelopeItemTitle}`,
|
||||
}))
|
||||
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_DELEGATED_OWNER_CREATED }, ({ data }) => ({
|
||||
anonymous: msg({
|
||||
message: `Document ownership delegated`,
|
||||
context: `Audit log format`,
|
||||
}),
|
||||
identified: msg`The document ownership was delegated to ${data.delegatedOwnerName || data.delegatedOwnerEmail} on behalf of ${data.teamName}`,
|
||||
}))
|
||||
.exhaustive();
|
||||
|
||||
return {
|
||||
|
||||
@@ -18,6 +18,8 @@ const ZDocumentIdSchema = z.string().regex(/^document_\d+$/);
|
||||
const ZTemplateIdSchema = z.string().regex(/^template_\d+$/);
|
||||
const ZEnvelopeIdSchema = z.string().regex(/^envelope_.{2,}$/);
|
||||
|
||||
const MAX_ENVELOPE_IDS_PER_REQUEST = 20;
|
||||
|
||||
export type EnvelopeIdOptions =
|
||||
| {
|
||||
type: 'envelopeId';
|
||||
@@ -32,6 +34,20 @@ export type EnvelopeIdOptions =
|
||||
id: number;
|
||||
};
|
||||
|
||||
export type EnvelopeIdsOptions =
|
||||
| {
|
||||
type: 'envelopeId';
|
||||
ids: string[];
|
||||
}
|
||||
| {
|
||||
type: 'documentId';
|
||||
ids: number[];
|
||||
}
|
||||
| {
|
||||
type: 'templateId';
|
||||
ids: number[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses an unknown document or template ID.
|
||||
*
|
||||
@@ -89,6 +105,87 @@ export const unsafeBuildEnvelopeIdQuery = (
|
||||
.exhaustive();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses multiple document or template IDs and builds a query filter.
|
||||
*
|
||||
* This is UNSAFE because it does not validate access, it only validates ID format and builds the query.
|
||||
*
|
||||
* @throws AppError if any ID is invalid or if the array exceeds the maximum limit
|
||||
*/
|
||||
export const unsafeBuildEnvelopeIdsQuery = (
|
||||
options: EnvelopeIdsOptions,
|
||||
expectedEnvelopeType: EnvelopeType | null,
|
||||
) => {
|
||||
if (!options.ids || options.ids.length === 0) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
message: 'At least one ID is required',
|
||||
});
|
||||
}
|
||||
|
||||
if (options.ids.length > MAX_ENVELOPE_IDS_PER_REQUEST) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
message: `Cannot request more than ${MAX_ENVELOPE_IDS_PER_REQUEST} envelopes at once`,
|
||||
});
|
||||
}
|
||||
|
||||
return match(options)
|
||||
.with({ type: 'envelopeId' }, (value) => {
|
||||
const validatedIds: string[] = [];
|
||||
|
||||
for (const id of value.ids) {
|
||||
const parsed = ZEnvelopeIdSchema.safeParse(id);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
message: `Invalid envelope ID: ${id}`,
|
||||
});
|
||||
}
|
||||
|
||||
validatedIds.push(parsed.data);
|
||||
}
|
||||
|
||||
if (expectedEnvelopeType) {
|
||||
return {
|
||||
id: { in: validatedIds },
|
||||
type: expectedEnvelopeType,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id: { in: validatedIds },
|
||||
};
|
||||
})
|
||||
.with({ type: 'documentId' }, (value) => {
|
||||
if (expectedEnvelopeType && expectedEnvelopeType !== EnvelopeType.DOCUMENT) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
message: 'Invalid document ID type',
|
||||
});
|
||||
}
|
||||
|
||||
const secondaryIds = value.ids.map((id) => mapDocumentIdToSecondaryId(id));
|
||||
|
||||
return {
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
secondaryId: { in: secondaryIds },
|
||||
};
|
||||
})
|
||||
.with({ type: 'templateId' }, (value) => {
|
||||
if (expectedEnvelopeType && expectedEnvelopeType !== EnvelopeType.TEMPLATE) {
|
||||
throw new AppError(AppErrorCode.INVALID_BODY, {
|
||||
message: 'Invalid template ID type',
|
||||
});
|
||||
}
|
||||
|
||||
const secondaryIds = value.ids.map((id) => mapTemplateIdToSecondaryId(id));
|
||||
|
||||
return {
|
||||
type: EnvelopeType.TEMPLATE,
|
||||
secondaryId: { in: secondaryIds },
|
||||
};
|
||||
})
|
||||
.exhaustive();
|
||||
};
|
||||
|
||||
/**
|
||||
* Maps a legacy document ID number to an envelope secondary ID.
|
||||
*
|
||||
|
||||
@@ -117,6 +117,7 @@ export const generateDefaultOrganisationSettings = (): Omit<
|
||||
documentLanguage: 'en',
|
||||
documentTimezone: null, // Null means local timezone.
|
||||
documentDateFormat: DEFAULT_DOCUMENT_DATE_FORMAT,
|
||||
delegateDocumentOwnership: false,
|
||||
|
||||
includeSenderDetails: true,
|
||||
includeSigningCertificate: true,
|
||||
|
||||
@@ -184,6 +184,7 @@ export const generateDefaultTeamSettings = (): Omit<TeamGlobalSettings, 'id' | '
|
||||
documentLanguage: null,
|
||||
documentTimezone: null,
|
||||
documentDateFormat: null,
|
||||
delegateDocumentOwnership: null,
|
||||
|
||||
includeSenderDetails: null,
|
||||
includeSigningCertificate: null,
|
||||
|
||||
Reference in New Issue
Block a user