feat: document visibility (#1262)
Adds the ability to set a visibility scope for documents within teams.
This commit is contained in:
@@ -12,10 +12,12 @@ import { getDocumentById } from '@documenso/lib/server-only/document/get-documen
|
|||||||
import { getServerComponentFlag } from '@documenso/lib/server-only/feature-flags/get-server-component-feature-flag';
|
import { getServerComponentFlag } from '@documenso/lib/server-only/feature-flags/get-server-component-feature-flag';
|
||||||
import { getFieldsForDocument } from '@documenso/lib/server-only/field/get-fields-for-document';
|
import { getFieldsForDocument } from '@documenso/lib/server-only/field/get-fields-for-document';
|
||||||
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
|
import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document';
|
||||||
|
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
|
||||||
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
|
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
|
||||||
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
||||||
import { DocumentStatus } from '@documenso/prisma/client';
|
import { DocumentStatus } from '@documenso/prisma/client';
|
||||||
import type { Team, TeamEmail } from '@documenso/prisma/client';
|
import type { Team, TeamEmail } from '@documenso/prisma/client';
|
||||||
|
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import { Badge } from '@documenso/ui/primitives/badge';
|
import { Badge } from '@documenso/ui/primitives/badge';
|
||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
import { Card, CardContent } from '@documenso/ui/primitives/card';
|
||||||
@@ -39,7 +41,7 @@ export type DocumentPageViewProps = {
|
|||||||
params: {
|
params: {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
team?: Team & { teamEmail: TeamEmail | null };
|
team?: Team & { teamEmail: TeamEmail | null } & { currentTeamMember: { role: TeamMemberRole } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DocumentPageView = async ({ params, team }: DocumentPageViewProps) => {
|
export const DocumentPageView = async ({ params, team }: DocumentPageViewProps) => {
|
||||||
@@ -62,11 +64,35 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
|
|||||||
teamId: team?.id,
|
teamId: team?.id,
|
||||||
}).catch(() => null);
|
}).catch(() => null);
|
||||||
|
|
||||||
|
if (document?.teamId && !team?.url) {
|
||||||
|
redirect(documentRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const documentVisibility = document?.visibility;
|
||||||
|
const currentTeamMemberRole = team?.currentTeamMember?.role;
|
||||||
|
const isRecipient = document?.Recipient.find((recipient) => recipient.email === user.email);
|
||||||
|
let canAccessDocument = true;
|
||||||
|
|
||||||
|
if (team && !isRecipient) {
|
||||||
|
canAccessDocument = match([documentVisibility, currentTeamMemberRole])
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MANAGER], () => true)
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MEMBER], () => true)
|
||||||
|
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.MANAGER], () => true)
|
||||||
|
.with([DocumentVisibility.ADMIN, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.otherwise(() => false);
|
||||||
|
}
|
||||||
|
|
||||||
const isDocumentHistoryEnabled = await getServerComponentFlag(
|
const isDocumentHistoryEnabled = await getServerComponentFlag(
|
||||||
'app_document_page_view_history_sheet',
|
'app_document_page_view_history_sheet',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!document || !document.documentData) {
|
if (!document || !document.documentData || (team && !canAccessDocument)) {
|
||||||
|
redirect(documentRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (team && !canAccessDocument) {
|
||||||
redirect(documentRootPath);
|
redirect(documentRootPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ export const EditDocumentForm = ({
|
|||||||
data: {
|
data: {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
externalId: data.externalId || null,
|
externalId: data.externalId || null,
|
||||||
|
visibility: data.visibility,
|
||||||
globalAccessAuth: data.globalAccessAuth ?? null,
|
globalAccessAuth: data.globalAccessAuth ?? null,
|
||||||
globalActionAuth: data.globalActionAuth ?? null,
|
globalActionAuth: data.globalActionAuth ?? null,
|
||||||
},
|
},
|
||||||
@@ -360,6 +361,7 @@ export const EditDocumentForm = ({
|
|||||||
key={recipients.length}
|
key={recipients.length}
|
||||||
documentFlow={documentFlow.settings}
|
documentFlow={documentFlow.settings}
|
||||||
document={document}
|
document={document}
|
||||||
|
currentTeamMemberRole={team?.currentTeamMember?.role}
|
||||||
recipients={recipients}
|
recipients={recipients}
|
||||||
fields={fields}
|
fields={fields}
|
||||||
isDocumentEnterprise={isDocumentEnterprise}
|
isDocumentEnterprise={isDocumentEnterprise}
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ import { redirect } from 'next/navigation';
|
|||||||
|
|
||||||
import { Plural, Trans } from '@lingui/macro';
|
import { Plural, Trans } from '@lingui/macro';
|
||||||
import { ChevronLeft, Users2 } from 'lucide-react';
|
import { ChevronLeft, Users2 } from 'lucide-react';
|
||||||
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
import { isUserEnterprise } from '@documenso/ee/server-only/util/is-document-enterprise';
|
||||||
import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
|
import { DOCUMENSO_ENCRYPTION_KEY } from '@documenso/lib/constants/crypto';
|
||||||
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session';
|
||||||
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
|
import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id';
|
||||||
|
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
|
||||||
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
|
import { symmetricDecrypt } from '@documenso/lib/universal/crypto';
|
||||||
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
||||||
import type { Team } from '@documenso/prisma/client';
|
import type { Team } from '@documenso/prisma/client';
|
||||||
|
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
|
import { DocumentStatus as InternalDocumentStatus } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import { EditDocumentForm } from '~/app/(dashboard)/documents/[id]/edit-document';
|
import { EditDocumentForm } from '~/app/(dashboard)/documents/[id]/edit-document';
|
||||||
@@ -21,7 +24,7 @@ export type DocumentEditPageViewProps = {
|
|||||||
params: {
|
params: {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
team?: Team;
|
team?: Team & { currentTeamMember: { role: TeamMemberRole } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DocumentEditPageView = async ({ params, team }: DocumentEditPageViewProps) => {
|
export const DocumentEditPageView = async ({ params, team }: DocumentEditPageViewProps) => {
|
||||||
@@ -43,10 +46,34 @@ export const DocumentEditPageView = async ({ params, team }: DocumentEditPageVie
|
|||||||
teamId: team?.id,
|
teamId: team?.id,
|
||||||
}).catch(() => null);
|
}).catch(() => null);
|
||||||
|
|
||||||
|
if (document?.teamId && !team?.url) {
|
||||||
|
redirect(documentRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const documentVisibility = document?.visibility;
|
||||||
|
const currentTeamMemberRole = team?.currentTeamMember?.role;
|
||||||
|
const isRecipient = document?.Recipient.find((recipient) => recipient.email === user.email);
|
||||||
|
let canAccessDocument = true;
|
||||||
|
|
||||||
|
if (!isRecipient) {
|
||||||
|
canAccessDocument = match([documentVisibility, currentTeamMemberRole])
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MANAGER], () => true)
|
||||||
|
.with([DocumentVisibility.EVERYONE, TeamMemberRole.MEMBER], () => true)
|
||||||
|
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.with([DocumentVisibility.MANAGER_AND_ABOVE, TeamMemberRole.MANAGER], () => true)
|
||||||
|
.with([DocumentVisibility.ADMIN, TeamMemberRole.ADMIN], () => true)
|
||||||
|
.otherwise(() => false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!document) {
|
if (!document) {
|
||||||
redirect(documentRootPath);
|
redirect(documentRootPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (team && !canAccessDocument) {
|
||||||
|
redirect(documentRootPath);
|
||||||
|
}
|
||||||
|
|
||||||
if (document.status === InternalDocumentStatus.COMPLETED) {
|
if (document.status === InternalDocumentStatus.COMPLETED) {
|
||||||
redirect(`${documentRootPath}/${documentId}`);
|
redirect(`${documentRootPath}/${documentId}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import type { GetStatsInput } from '@documenso/lib/server-only/document/get-stat
|
|||||||
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
import { getStats } from '@documenso/lib/server-only/document/get-stats';
|
||||||
import { parseToIntegerArray } from '@documenso/lib/utils/params';
|
import { parseToIntegerArray } from '@documenso/lib/utils/params';
|
||||||
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
|
||||||
import type { Team, TeamEmail } from '@documenso/prisma/client';
|
import type { Team, TeamEmail, TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
||||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from '@documenso/ui/primitives/avatar';
|
import { Avatar, AvatarFallback, AvatarImage } from '@documenso/ui/primitives/avatar';
|
||||||
@@ -33,7 +33,7 @@ export type DocumentsPageViewProps = {
|
|||||||
perPage?: string;
|
perPage?: string;
|
||||||
senderIds?: string;
|
senderIds?: string;
|
||||||
};
|
};
|
||||||
team?: Team & { teamEmail?: TeamEmail | null };
|
team?: Team & { teamEmail?: TeamEmail | null } & { currentTeamMember?: { role: TeamMemberRole } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DocumentsPageView = async ({ searchParams = {}, team }: DocumentsPageViewProps) => {
|
export const DocumentsPageView = async ({ searchParams = {}, team }: DocumentsPageViewProps) => {
|
||||||
@@ -47,6 +47,7 @@ export const DocumentsPageView = async ({ searchParams = {}, team }: DocumentsPa
|
|||||||
const currentTeam = team
|
const currentTeam = team
|
||||||
? { id: team.id, url: team.url, teamEmail: team.teamEmail?.email }
|
? { id: team.id, url: team.url, teamEmail: team.teamEmail?.email }
|
||||||
: undefined;
|
: undefined;
|
||||||
|
const currentTeamMemberRole = team?.currentTeamMember?.role;
|
||||||
|
|
||||||
const getStatOptions: GetStatsInput = {
|
const getStatOptions: GetStatsInput = {
|
||||||
user,
|
user,
|
||||||
@@ -58,6 +59,9 @@ export const DocumentsPageView = async ({ searchParams = {}, team }: DocumentsPa
|
|||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
teamEmail: team.teamEmail?.email,
|
teamEmail: team.teamEmail?.email,
|
||||||
senderIds,
|
senderIds,
|
||||||
|
currentTeamMemberRole,
|
||||||
|
currentUserEmail: user.email,
|
||||||
|
userId: user.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -335,6 +335,23 @@ export const DocumentHistorySheet = ({
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
.with(
|
||||||
|
{ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED },
|
||||||
|
({ data }) => (
|
||||||
|
<DocumentHistorySheetChanges
|
||||||
|
values={[
|
||||||
|
{
|
||||||
|
key: 'Old',
|
||||||
|
value: data.from,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'New',
|
||||||
|
value: data.to,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)
|
||||||
.exhaustive()}
|
.exhaustive()}
|
||||||
|
|
||||||
{isUserDetailsVisible && (
|
{isUserDetailsVisible && (
|
||||||
|
|||||||
@@ -3,14 +3,14 @@
|
|||||||
import { createContext, useContext } from 'react';
|
import { createContext, useContext } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import type { Team } from '@documenso/prisma/client';
|
import type { GetTeamResponse } from '@documenso/lib/server-only/team/get-team';
|
||||||
|
|
||||||
interface TeamProviderProps {
|
interface TeamProviderProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
team: Team;
|
team: GetTeamResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TeamContext = createContext<Team | null>(null);
|
const TeamContext = createContext<GetTeamResponse | null>(null);
|
||||||
|
|
||||||
export const useCurrentTeam = () => {
|
export const useCurrentTeam = () => {
|
||||||
const context = useContext(TeamContext);
|
const context = useContext(TeamContext);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { expect, test } from '@playwright/test';
|
import { expect, test } from '@playwright/test';
|
||||||
|
|
||||||
import { DocumentStatus } from '@documenso/prisma/client';
|
import { DocumentStatus, TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import { seedDocuments, seedTeamDocuments } from '@documenso/prisma/seed/documents';
|
import { seedDocuments, seedTeamDocuments } from '@documenso/prisma/seed/documents';
|
||||||
import { seedTeamEmail } from '@documenso/prisma/seed/teams';
|
import { seedTeam, seedTeamEmail, seedTeamMember } from '@documenso/prisma/seed/teams';
|
||||||
import { seedUser } from '@documenso/prisma/seed/users';
|
import { seedUser } from '@documenso/prisma/seed/users';
|
||||||
|
|
||||||
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
import { apiSignin, apiSignout } from '../fixtures/authentication';
|
||||||
@@ -355,3 +355,354 @@ test('[TEAMS]: delete completed team document', async ({ page }) => {
|
|||||||
await apiSignout({ page });
|
await apiSignout({ page });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: check document visibility based on team member role', async ({ page }) => {
|
||||||
|
const team = await seedTeam();
|
||||||
|
|
||||||
|
// Seed users with different roles
|
||||||
|
const adminUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.ADMIN,
|
||||||
|
});
|
||||||
|
|
||||||
|
const managerUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.MANAGER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const memberUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.MEMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const outsideUser = await seedUser();
|
||||||
|
|
||||||
|
// Seed documents with different visibility levels
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'EVERYONE',
|
||||||
|
title: 'Document Visible to Everyone',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'MANAGER_AND_ABOVE',
|
||||||
|
title: 'Document Visible to Manager and Above',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'ADMIN',
|
||||||
|
title: 'Document Visible to Admin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [outsideUser],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'ADMIN',
|
||||||
|
title: 'Document Visible to Admin with Recipient',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Test cases for each role
|
||||||
|
const testCases = [
|
||||||
|
{
|
||||||
|
user: adminUser,
|
||||||
|
expectedDocuments: [
|
||||||
|
'Document Visible to Everyone',
|
||||||
|
'Document Visible to Manager and Above',
|
||||||
|
'Document Visible to Admin',
|
||||||
|
'Document Visible to Admin with Recipient',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: managerUser,
|
||||||
|
expectedDocuments: ['Document Visible to Everyone', 'Document Visible to Manager and Above'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: memberUser,
|
||||||
|
expectedDocuments: ['Document Visible to Everyone'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: outsideUser,
|
||||||
|
expectedDocuments: ['Document Visible to Admin with Recipient'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const testCase of testCases) {
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: testCase.user.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the user sees the expected documents
|
||||||
|
for (const documentTitle of testCase.expectedDocuments) {
|
||||||
|
await expect(page.getByRole('link', { name: documentTitle, exact: true })).toBeVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: ensure recipient can see document regardless of visibility', async ({ page }) => {
|
||||||
|
const team = await seedTeam();
|
||||||
|
|
||||||
|
// Seed a member user
|
||||||
|
const memberUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.MEMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Seed a document with ADMIN visibility but make the member user a recipient
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [memberUser],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'ADMIN',
|
||||||
|
title: 'Admin Document with Member Recipient',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: memberUser.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the member user can see the document
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Admin Document with Member Recipient', exact: true }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: check that members cannot see ADMIN-only documents', async ({ page }) => {
|
||||||
|
const team = await seedTeam();
|
||||||
|
|
||||||
|
// Seed a member user
|
||||||
|
const memberUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.MEMBER,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Seed an ADMIN-only document
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'ADMIN',
|
||||||
|
title: 'Admin Only Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: memberUser.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the member user cannot see the ADMIN-only document
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Admin Only Document', exact: true }),
|
||||||
|
).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: check that managers cannot see ADMIN-only documents', async ({ page }) => {
|
||||||
|
const team = await seedTeam();
|
||||||
|
|
||||||
|
// Seed a manager user
|
||||||
|
const managerUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.MANAGER,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Seed an ADMIN-only document
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'ADMIN',
|
||||||
|
title: 'Admin Only Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: managerUser.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the manager user cannot see the ADMIN-only document
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Admin Only Document', exact: true }),
|
||||||
|
).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: check that admin can see MANAGER_AND_ABOVE documents', async ({ page }) => {
|
||||||
|
const team = await seedTeam();
|
||||||
|
|
||||||
|
// Seed an admin user
|
||||||
|
const adminUser = await seedTeamMember({
|
||||||
|
teamId: team.id,
|
||||||
|
role: TeamMemberRole.ADMIN,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Seed a MANAGER_AND_ABOVE document
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: team.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'MANAGER_AND_ABOVE',
|
||||||
|
title: 'Manager and Above Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: adminUser.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the admin user can see the MANAGER_AND_ABOVE document
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Manager and Above Document', exact: true }),
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: users cannot see documents from other teams', async ({ page }) => {
|
||||||
|
// Seed two teams with documents
|
||||||
|
const { team: teamA, teamMember2: teamAMember } = await seedTeamDocuments();
|
||||||
|
const { team: teamB, teamMember2: teamBMember } = await seedTeamDocuments();
|
||||||
|
|
||||||
|
// Seed a document in team B
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: teamB.owner,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: teamB.id,
|
||||||
|
visibility: 'EVERYONE',
|
||||||
|
title: 'Team B Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Sign in as a member of team A
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: teamAMember.email,
|
||||||
|
redirectPath: `/t/${teamA.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that the user cannot see the document from team B
|
||||||
|
await expect(page.getByRole('link', { name: 'Team B Document', exact: true })).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[TEAMS]: personal documents are not visible in team context', async ({ page }) => {
|
||||||
|
// Seed a team and a user with personal documents
|
||||||
|
const { team, teamMember2 } = await seedTeamDocuments();
|
||||||
|
const personalUser = await seedUser();
|
||||||
|
|
||||||
|
// Seed a personal document for teamMember2
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: teamMember2,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: null, // Indicates a personal document
|
||||||
|
visibility: 'EVERYONE',
|
||||||
|
title: 'Personal Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Sign in as teamMember2 in the team context
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: teamMember2.email,
|
||||||
|
redirectPath: `/t/${team.url}/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that the personal document is not visible in the team context
|
||||||
|
await expect(
|
||||||
|
page.getByRole('link', { name: 'Personal Document', exact: true }),
|
||||||
|
).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('[PERSONAL]: team documents are not visible in personal account', async ({ page }) => {
|
||||||
|
// Seed a team and a user with personal documents
|
||||||
|
const { team, teamMember2 } = await seedTeamDocuments();
|
||||||
|
|
||||||
|
// Seed a team document
|
||||||
|
await seedDocuments([
|
||||||
|
{
|
||||||
|
sender: teamMember2,
|
||||||
|
recipients: [],
|
||||||
|
type: DocumentStatus.COMPLETED,
|
||||||
|
documentOptions: {
|
||||||
|
teamId: team.id,
|
||||||
|
visibility: 'EVERYONE',
|
||||||
|
title: 'Team Document',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Sign in as teamMember2 in the personal context
|
||||||
|
await apiSignin({
|
||||||
|
page,
|
||||||
|
email: teamMember2.email,
|
||||||
|
redirectPath: `/documents?status=COMPLETED`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that the team document is not visible in the personal context
|
||||||
|
await expect(page.getByRole('link', { name: 'Team Document', exact: true })).not.toBeVisible();
|
||||||
|
|
||||||
|
await apiSignout({ page });
|
||||||
|
});
|
||||||
|
|||||||
23
packages/lib/constants/document-visibility.ts
Normal file
23
packages/lib/constants/document-visibility.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
|
||||||
|
|
||||||
|
import type { TDocumentVisibility } from '../types/document-visibility';
|
||||||
|
|
||||||
|
type DocumentVisibilityTypeData = {
|
||||||
|
key: TDocumentVisibility;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DOCUMENT_VISIBILITY: Record<string, DocumentVisibilityTypeData> = {
|
||||||
|
[DocumentVisibility.ADMIN]: {
|
||||||
|
key: DocumentVisibility.ADMIN,
|
||||||
|
value: 'Admins only',
|
||||||
|
},
|
||||||
|
[DocumentVisibility.EVERYONE]: {
|
||||||
|
key: DocumentVisibility.EVERYONE,
|
||||||
|
value: 'Everyone',
|
||||||
|
},
|
||||||
|
[DocumentVisibility.MANAGER_AND_ABOVE]: {
|
||||||
|
key: DocumentVisibility.MANAGER_AND_ABOVE,
|
||||||
|
value: 'Managers and above',
|
||||||
|
},
|
||||||
|
} satisfies Record<TDocumentVisibility, DocumentVisibilityTypeData>;
|
||||||
@@ -2,10 +2,11 @@ import { DateTime } from 'luxon';
|
|||||||
import { P, match } from 'ts-pattern';
|
import { P, match } from 'ts-pattern';
|
||||||
|
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import { RecipientRole, SigningStatus } from '@documenso/prisma/client';
|
import { RecipientRole, SigningStatus, TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import type { Document, Prisma, Team, TeamEmail, User } from '@documenso/prisma/client';
|
import type { Document, Prisma, Team, TeamEmail, User } from '@documenso/prisma/client';
|
||||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||||
|
|
||||||
|
import { DocumentVisibility } from '../../types/document-visibility';
|
||||||
import type { FindResultSet } from '../../types/find-result-set';
|
import type { FindResultSet } from '../../types/find-result-set';
|
||||||
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
|
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
|
||||||
|
|
||||||
@@ -58,6 +59,14 @@ export const findDocuments = async ({
|
|||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
teamEmail: true,
|
teamEmail: true,
|
||||||
|
members: {
|
||||||
|
where: {
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
role: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -70,6 +79,7 @@ export const findDocuments = async ({
|
|||||||
|
|
||||||
const orderByColumn = orderBy?.column ?? 'createdAt';
|
const orderByColumn = orderBy?.column ?? 'createdAt';
|
||||||
const orderByDirection = orderBy?.direction ?? 'desc';
|
const orderByDirection = orderBy?.direction ?? 'desc';
|
||||||
|
const teamMemberRole = team?.members[0].role ?? null;
|
||||||
|
|
||||||
const termFilters = match(term)
|
const termFilters = match(term)
|
||||||
.with(P.string.minLength(1), () => {
|
.with(P.string.minLength(1), () => {
|
||||||
@@ -82,7 +92,37 @@ export const findDocuments = async ({
|
|||||||
})
|
})
|
||||||
.otherwise(() => undefined);
|
.otherwise(() => undefined);
|
||||||
|
|
||||||
const filters = team ? findTeamDocumentsFilter(status, team) : findDocumentsFilter(status, user);
|
const visibilityFilters = [
|
||||||
|
match(teamMemberRole)
|
||||||
|
.with(TeamMemberRole.ADMIN, () => ({
|
||||||
|
visibility: {
|
||||||
|
in: [
|
||||||
|
DocumentVisibility.EVERYONE,
|
||||||
|
DocumentVisibility.MANAGER_AND_ABOVE,
|
||||||
|
DocumentVisibility.ADMIN,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.with(TeamMemberRole.MANAGER, () => ({
|
||||||
|
visibility: {
|
||||||
|
in: [DocumentVisibility.EVERYONE, DocumentVisibility.MANAGER_AND_ABOVE],
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
.otherwise(() => ({ visibility: DocumentVisibility.EVERYONE })),
|
||||||
|
{
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let filters: Prisma.DocumentWhereInput | null = findDocumentsFilter(status, user);
|
||||||
|
|
||||||
|
if (team) {
|
||||||
|
filters = findTeamDocumentsFilter(status, team, visibilityFilters);
|
||||||
|
}
|
||||||
|
|
||||||
if (filters === null) {
|
if (filters === null) {
|
||||||
return {
|
return {
|
||||||
@@ -148,9 +188,7 @@ export const findDocuments = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const whereClause: Prisma.DocumentWhereInput = {
|
const whereClause: Prisma.DocumentWhereInput = {
|
||||||
...termFilters,
|
AND: [{ ...termFilters }, { ...filters }, { ...deletedFilter }],
|
||||||
...filters,
|
|
||||||
...deletedFilter,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (period) {
|
if (period) {
|
||||||
@@ -333,6 +371,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
|
|||||||
const findTeamDocumentsFilter = (
|
const findTeamDocumentsFilter = (
|
||||||
status: ExtendedDocumentStatus,
|
status: ExtendedDocumentStatus,
|
||||||
team: Team & { teamEmail: TeamEmail | null },
|
team: Team & { teamEmail: TeamEmail | null },
|
||||||
|
visibilityFilters: Prisma.DocumentWhereInput[],
|
||||||
) => {
|
) => {
|
||||||
const teamEmail = team.teamEmail?.email ?? null;
|
const teamEmail = team.teamEmail?.email ?? null;
|
||||||
|
|
||||||
@@ -343,6 +382,7 @@ const findTeamDocumentsFilter = (
|
|||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -358,6 +398,7 @@ const findTeamDocumentsFilter = (
|
|||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Filter to display all documents that have been sent by the team email.
|
// Filter to display all documents that have been sent by the team email.
|
||||||
@@ -365,6 +406,7 @@ const findTeamDocumentsFilter = (
|
|||||||
User: {
|
User: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,6 +431,7 @@ const findTeamDocumentsFilter = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.with(ExtendedDocumentStatus.DRAFT, () => {
|
.with(ExtendedDocumentStatus.DRAFT, () => {
|
||||||
@@ -397,6 +440,7 @@ const findTeamDocumentsFilter = (
|
|||||||
{
|
{
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
status: ExtendedDocumentStatus.DRAFT,
|
status: ExtendedDocumentStatus.DRAFT,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -407,6 +451,7 @@ const findTeamDocumentsFilter = (
|
|||||||
User: {
|
User: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +463,7 @@ const findTeamDocumentsFilter = (
|
|||||||
{
|
{
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
status: ExtendedDocumentStatus.PENDING,
|
status: ExtendedDocumentStatus.PENDING,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -436,11 +482,13 @@ const findTeamDocumentsFilter = (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
User: {
|
User: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -454,6 +502,7 @@ const findTeamDocumentsFilter = (
|
|||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@@ -466,11 +515,13 @@ const findTeamDocumentsFilter = (
|
|||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
User: {
|
User: {
|
||||||
email: teamEmail,
|
email: teamEmail,
|
||||||
},
|
},
|
||||||
|
OR: visibilityFilters,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
import type { Prisma } from '@documenso/prisma/client';
|
import type { Prisma } from '@documenso/prisma/client';
|
||||||
|
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
import { DocumentVisibility } from '../../types/document-visibility';
|
||||||
import { getTeamById } from '../team/get-team';
|
import { getTeamById } from '../team/get-team';
|
||||||
|
|
||||||
export type GetDocumentByIdOptions = {
|
export type GetDocumentByIdOptions = {
|
||||||
@@ -28,6 +32,11 @@ export const getDocumentById = async ({ id, userId, teamId }: GetDocumentByIdOpt
|
|||||||
email: true,
|
email: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Recipient: {
|
||||||
|
select: {
|
||||||
|
email: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
team: {
|
team: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -115,5 +124,35 @@ export const getDocumentWhereInput = async ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return documentWhereInput;
|
const user = await prisma.user.findFirstOrThrow({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const visibilityFilters = [
|
||||||
|
...match(team.currentTeamMember?.role)
|
||||||
|
.with(TeamMemberRole.ADMIN, () => [
|
||||||
|
{ visibility: DocumentVisibility.EVERYONE },
|
||||||
|
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
||||||
|
{ visibility: DocumentVisibility.ADMIN },
|
||||||
|
])
|
||||||
|
.with(TeamMemberRole.MANAGER, () => [
|
||||||
|
{ visibility: DocumentVisibility.EVERYONE },
|
||||||
|
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
||||||
|
])
|
||||||
|
.otherwise(() => [{ visibility: DocumentVisibility.EVERYONE }]),
|
||||||
|
{
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: user.email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...documentWhereInput,
|
||||||
|
OR: [...visibilityFilters],
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
import { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import type { Prisma, User } from '@documenso/prisma/client';
|
import type { Prisma, User } from '@documenso/prisma/client';
|
||||||
import { SigningStatus } from '@documenso/prisma/client';
|
import { SigningStatus } from '@documenso/prisma/client';
|
||||||
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
import { isExtendedDocumentStatus } from '@documenso/prisma/guards/is-extended-document-status';
|
||||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||||
|
|
||||||
|
import { DocumentVisibility } from '../../types/document-visibility';
|
||||||
|
|
||||||
export type GetStatsInput = {
|
export type GetStatsInput = {
|
||||||
user: User;
|
user: User;
|
||||||
team?: Omit<GetTeamCountsOption, 'createdAt'>;
|
team?: Omit<GetTeamCountsOption, 'createdAt'>;
|
||||||
@@ -27,7 +31,7 @@ export const getStats = async ({ user, period, ...options }: GetStatsInput) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [ownerCounts, notSignedCounts, hasSignedCounts] = await (options.team
|
const [ownerCounts, notSignedCounts, hasSignedCounts] = await (options.team
|
||||||
? getTeamCounts({ ...options.team, createdAt })
|
? getTeamCounts({ ...options.team, createdAt, currentUserEmail: user.email, userId: user.id })
|
||||||
: getCounts({ user, createdAt }));
|
: getCounts({ user, createdAt }));
|
||||||
|
|
||||||
const stats: Record<ExtendedDocumentStatus, number> = {
|
const stats: Record<ExtendedDocumentStatus, number> = {
|
||||||
@@ -147,7 +151,10 @@ type GetTeamCountsOption = {
|
|||||||
teamId: number;
|
teamId: number;
|
||||||
teamEmail?: string;
|
teamEmail?: string;
|
||||||
senderIds?: number[];
|
senderIds?: number[];
|
||||||
|
currentUserEmail: string;
|
||||||
|
userId: number;
|
||||||
createdAt: Prisma.DocumentWhereInput['createdAt'];
|
createdAt: Prisma.DocumentWhereInput['createdAt'];
|
||||||
|
currentTeamMemberRole?: TeamMemberRole;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTeamCounts = async (options: GetTeamCountsOption) => {
|
const getTeamCounts = async (options: GetTeamCountsOption) => {
|
||||||
@@ -172,6 +179,49 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
|
|||||||
let notSignedCountsGroupByArgs = null;
|
let notSignedCountsGroupByArgs = null;
|
||||||
let hasSignedCountsGroupByArgs = null;
|
let hasSignedCountsGroupByArgs = null;
|
||||||
|
|
||||||
|
const visibilityFilters = [
|
||||||
|
...match(options.currentTeamMemberRole)
|
||||||
|
.with(TeamMemberRole.ADMIN, () => [
|
||||||
|
{ visibility: DocumentVisibility.EVERYONE },
|
||||||
|
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
||||||
|
{ visibility: DocumentVisibility.ADMIN },
|
||||||
|
])
|
||||||
|
.with(TeamMemberRole.MANAGER, () => [
|
||||||
|
{ visibility: DocumentVisibility.EVERYONE },
|
||||||
|
{ visibility: DocumentVisibility.MANAGER_AND_ABOVE },
|
||||||
|
])
|
||||||
|
.otherwise(() => [{ visibility: DocumentVisibility.EVERYONE }]),
|
||||||
|
];
|
||||||
|
|
||||||
|
ownerCountsWhereInput = {
|
||||||
|
...ownerCountsWhereInput,
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
visibility: {
|
||||||
|
in: visibilityFilters.map((filter) => filter.visibility),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Recipient: {
|
||||||
|
none: {
|
||||||
|
email: options.currentUserEmail,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Recipient: {
|
||||||
|
some: {
|
||||||
|
email: options.currentUserEmail,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
if (teamEmail) {
|
if (teamEmail) {
|
||||||
ownerCountsWhereInput = {
|
ownerCountsWhereInput = {
|
||||||
userId: userIdWhereClause,
|
userId: userIdWhereClause,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { RequestMetadata } from '@documenso/lib/universal/extract-request-m
|
|||||||
import type { CreateDocumentAuditLogDataResponse } from '@documenso/lib/utils/document-audit-logs';
|
import type { CreateDocumentAuditLogDataResponse } from '@documenso/lib/utils/document-audit-logs';
|
||||||
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
import type { DocumentVisibility } from '@documenso/prisma/client';
|
||||||
import { DocumentStatus } from '@documenso/prisma/client';
|
import { DocumentStatus } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||||
@@ -19,6 +20,7 @@ export type UpdateDocumentSettingsOptions = {
|
|||||||
data: {
|
data: {
|
||||||
title?: string;
|
title?: string;
|
||||||
externalId?: string | null;
|
externalId?: string | null;
|
||||||
|
visibility?: string | null;
|
||||||
globalAccessAuth?: TDocumentAccessAuthTypes | null;
|
globalAccessAuth?: TDocumentAccessAuthTypes | null;
|
||||||
globalActionAuth?: TDocumentActionAuthTypes | null;
|
globalActionAuth?: TDocumentActionAuthTypes | null;
|
||||||
};
|
};
|
||||||
@@ -95,6 +97,7 @@ export const updateDocumentSettings = async ({
|
|||||||
const isExternalIdSame = data.externalId === document.externalId;
|
const isExternalIdSame = data.externalId === document.externalId;
|
||||||
const isGlobalAccessSame = documentGlobalAccessAuth === newGlobalAccessAuth;
|
const isGlobalAccessSame = documentGlobalAccessAuth === newGlobalAccessAuth;
|
||||||
const isGlobalActionSame = documentGlobalActionAuth === newGlobalActionAuth;
|
const isGlobalActionSame = documentGlobalActionAuth === newGlobalActionAuth;
|
||||||
|
const isDocumentVisibilitySame = data.visibility === document.visibility;
|
||||||
|
|
||||||
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
|
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
|
||||||
|
|
||||||
@@ -165,6 +168,21 @@ export const updateDocumentSettings = async ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isDocumentVisibilitySame) {
|
||||||
|
auditLogs.push(
|
||||||
|
createDocumentAuditLogData({
|
||||||
|
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED,
|
||||||
|
documentId,
|
||||||
|
user,
|
||||||
|
requestMetadata,
|
||||||
|
data: {
|
||||||
|
from: document.visibility,
|
||||||
|
to: data.visibility || '',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Early return if nothing is required.
|
// Early return if nothing is required.
|
||||||
if (auditLogs.length === 0) {
|
if (auditLogs.length === 0) {
|
||||||
return document;
|
return document;
|
||||||
@@ -183,6 +201,7 @@ export const updateDocumentSettings = async ({
|
|||||||
data: {
|
data: {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
externalId: data.externalId || null,
|
externalId: data.externalId || null,
|
||||||
|
visibility: data.visibility as DocumentVisibility,
|
||||||
authOptions,
|
authOptions,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ export type GetTeamByIdOptions = {
|
|||||||
teamId: number;
|
teamId: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GetTeamResponse = Awaited<ReturnType<typeof getTeamById>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a team given a teamId.
|
* Get a team given a teamId.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,125 +20,125 @@ msgstr ""
|
|||||||
|
|
||||||
#: packages/ui/primitives/data-table-pagination.tsx:30
|
#: packages/ui/primitives/data-table-pagination.tsx:30
|
||||||
msgid "{0} of {1} row(s) selected."
|
msgid "{0} of {1} row(s) selected."
|
||||||
msgstr "{0} von {1} Zeile(n) ausgewählt."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table-pagination.tsx:41
|
#: packages/ui/primitives/data-table-pagination.tsx:41
|
||||||
msgid "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
|
msgid "{visibleRows, plural, one {Showing # result.} other {Showing # results.}}"
|
||||||
msgstr "{visibleRows, plural, one {Eine # Ergebnis wird angezeigt.} other {# Ergebnisse werden angezeigt.}}"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:53
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:53
|
||||||
msgid "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
|
msgid "<0>Inherit authentication method</0> - Use the global action signing authentication method configured in the \"General Settings\" step"
|
||||||
msgstr "<0>Authentifizierungsmethode erben</0> - Verwenden Sie die in den \"Allgemeinen Einstellungen\" konfigurierte globale Aktionssignatur-Authentifizierungsmethode"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:95
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:95
|
||||||
msgid "<0>No restrictions</0> - No authentication required"
|
msgid "<0>No restrictions</0> - No authentication required"
|
||||||
msgstr "<0>Keine Einschränkungen</0> - Keine Authentifizierung erforderlich"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:77
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:77
|
||||||
msgid "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
|
msgid "<0>No restrictions</0> - The document can be accessed directly by the URL sent to the recipient"
|
||||||
msgstr "<0>Keine Einschränkungen</0> - Das Dokument kann direkt über die dem Empfänger gesendete URL abgerufen werden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:75
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:75
|
||||||
msgid "<0>None</0> - No authentication required"
|
msgid "<0>None</0> - No authentication required"
|
||||||
msgstr "<0>Keine</0> - Keine Authentifizierung erforderlich"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:89
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:89
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:69
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:69
|
||||||
msgid "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
|
msgid "<0>Require 2FA</0> - The recipient must have an account and 2FA enabled via their settings"
|
||||||
msgstr "<0>2FA erforderlich</0> - Der Empfänger muss ein Konto haben und die 2FA über seine Einstellungen aktiviert haben"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:72
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:72
|
||||||
msgid "<0>Require account</0> - The recipient must be signed in to view the document"
|
msgid "<0>Require account</0> - The recipient must be signed in to view the document"
|
||||||
msgstr "<0>Konto erforderlich</0> - Der Empfänger muss angemeldet sein, um das Dokument anzeigen zu können"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:83
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:83
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:63
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:63
|
||||||
msgid "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
|
msgid "<0>Require passkey</0> - The recipient must have an account and passkey configured via their settings"
|
||||||
msgstr "<0>Passkey erforderlich</0> - Der Empfänger muss ein Konto haben und den Passkey über seine Einstellungen konfiguriert haben"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:69
|
#: packages/ui/primitives/document-dropzone.tsx:69
|
||||||
msgid "Add a document"
|
msgid "Add a document"
|
||||||
msgstr "Dokument hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:305
|
#: packages/ui/primitives/document-flow/add-settings.tsx:336
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
|
||||||
msgid "Add a URL to redirect the user to once the document is signed"
|
msgid "Add a URL to redirect the user to once the document is signed"
|
||||||
msgstr "Fügen Sie eine URL hinzu, um den Benutzer nach der Unterzeichnung des Dokuments weiterzuleiten"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:217
|
#: packages/ui/primitives/document-flow/add-settings.tsx:248
|
||||||
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
|
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
|
||||||
msgstr "Fügen Sie dem Dokument eine externe ID hinzu. Diese kann verwendet werden, um das Dokument in externen Systemen zu identifizieren."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:256
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:256
|
||||||
msgid "Add an external ID to the template. This can be used to identify in external systems."
|
msgid "Add an external ID to the template. This can be used to identify in external systems."
|
||||||
msgstr "Fügen Sie der Vorlage eine externe ID hinzu. Diese kann zur Identifizierung in externen Systemen verwendet werden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:177
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:177
|
||||||
msgid "Add another option"
|
msgid "Add another option"
|
||||||
msgstr "Weitere Option hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:230
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:230
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:167
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:167
|
||||||
msgid "Add another value"
|
msgid "Add another value"
|
||||||
msgstr "Weiteren Wert hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:653
|
#: packages/ui/primitives/document-flow/add-signers.tsx:653
|
||||||
msgid "Add myself"
|
msgid "Add myself"
|
||||||
msgstr "Mich selbst hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:637
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:637
|
||||||
msgid "Add Myself"
|
msgid "Add Myself"
|
||||||
msgstr "Mich hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:623
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:623
|
||||||
msgid "Add Placeholder Recipient"
|
msgid "Add Placeholder Recipient"
|
||||||
msgstr "Platzhalterempfänger hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:642
|
#: packages/ui/primitives/document-flow/add-signers.tsx:642
|
||||||
msgid "Add Signer"
|
msgid "Add Signer"
|
||||||
msgstr "Unterzeichner hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:70
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:70
|
||||||
msgid "Add text"
|
msgid "Add text"
|
||||||
msgstr "Text hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:75
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:75
|
||||||
msgid "Add text to the field"
|
msgid "Add text to the field"
|
||||||
msgstr "Text zum Feld hinzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/teams.ts:10
|
#: packages/lib/constants/teams.ts:10
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Admin"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:199
|
#: packages/ui/primitives/document-flow/add-settings.tsx:230
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
|
||||||
msgid "Advanced Options"
|
msgid "Advanced Options"
|
||||||
msgstr "Erweiterte Optionen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:522
|
#: packages/ui/primitives/document-flow/add-fields.tsx:522
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:402
|
||||||
msgid "Advanced settings"
|
msgid "Advanced settings"
|
||||||
msgstr "Erweiterte Einstellungen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:21
|
#: packages/lib/constants/template.ts:21
|
||||||
msgid "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
|
msgid "After submission, a document will be automatically generated and added to your documents page. You will also receive a notification via email."
|
||||||
msgstr "Nach der Übermittlung wird ein Dokument automatisch generiert und zu Ihrer Dokumentenseite hinzugefügt. Sie erhalten außerdem eine Benachrichtigung per E-Mail."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:8
|
#: packages/lib/constants/recipient-roles.ts:8
|
||||||
msgid "Approve"
|
msgid "Approve"
|
||||||
msgstr "Genehmigen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:9
|
#: packages/lib/constants/recipient-roles.ts:9
|
||||||
msgid "Approved"
|
msgid "Approved"
|
||||||
msgstr "Genehmigt"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:11
|
#: packages/lib/constants/recipient-roles.ts:11
|
||||||
msgid "Approver"
|
msgid "Approver"
|
||||||
msgstr "Genehmiger"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:10
|
#: packages/lib/constants/recipient-roles.ts:10
|
||||||
msgid "Approving"
|
msgid "Approving"
|
||||||
msgstr "Genehmigung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/signature-pad/signature-pad.tsx:276
|
#: packages/ui/primitives/signature-pad/signature-pad.tsx:276
|
||||||
msgid "Black"
|
msgid "Black"
|
||||||
@@ -151,115 +151,115 @@ msgstr ""
|
|||||||
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:287
|
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:287
|
||||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:58
|
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:58
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:194
|
#: packages/ui/primitives/document-flow/add-signers.tsx:194
|
||||||
msgid "Cannot remove signer"
|
msgid "Cannot remove signer"
|
||||||
msgstr "Unterzeichner kann nicht entfernt werden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:17
|
#: packages/lib/constants/recipient-roles.ts:17
|
||||||
msgid "Cc"
|
msgid "Cc"
|
||||||
msgstr "Cc"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:14
|
#: packages/lib/constants/recipient-roles.ts:14
|
||||||
#: packages/lib/constants/recipient-roles.ts:16
|
#: packages/lib/constants/recipient-roles.ts:16
|
||||||
msgid "CC"
|
msgid "CC"
|
||||||
msgstr "CC"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:15
|
#: packages/lib/constants/recipient-roles.ts:15
|
||||||
msgid "CC'd"
|
msgid "CC'd"
|
||||||
msgstr "CC'd"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:83
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:83
|
||||||
msgid "Character Limit"
|
msgid "Character Limit"
|
||||||
msgstr "Zeichenbeschränkung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:944
|
#: packages/ui/primitives/document-flow/add-fields.tsx:944
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:788
|
||||||
msgid "Checkbox"
|
msgid "Checkbox"
|
||||||
msgstr "Checkbox"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:195
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:195
|
||||||
msgid "Checkbox values"
|
msgid "Checkbox values"
|
||||||
msgstr "Checkbox-Werte"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table.tsx:156
|
#: packages/ui/primitives/data-table.tsx:156
|
||||||
msgid "Clear filters"
|
msgid "Clear filters"
|
||||||
msgstr "Filter löschen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/signature-pad/signature-pad.tsx:310
|
#: packages/ui/primitives/signature-pad/signature-pad.tsx:310
|
||||||
msgid "Clear Signature"
|
msgid "Clear Signature"
|
||||||
msgstr "Unterschrift löschen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:394
|
#: packages/ui/primitives/document-flow/add-signature.tsx:394
|
||||||
msgid "Click to insert field"
|
msgid "Click to insert field"
|
||||||
msgstr "Klicken, um das Feld einzufügen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
|
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:44
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Schließen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:12
|
#: packages/lib/constants/template.ts:12
|
||||||
msgid "Configure Direct Recipient"
|
msgid "Configure Direct Recipient"
|
||||||
msgstr "Direkten Empfänger konfigurieren"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:523
|
#: packages/ui/primitives/document-flow/add-fields.tsx:523
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:403
|
||||||
msgid "Configure the {0} field"
|
msgid "Configure the {0} field"
|
||||||
msgstr "Konfigurieren Sie das Feld {0}"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/document-flow-root.tsx:141
|
#: packages/ui/primitives/document-flow/document-flow-root.tsx:141
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr "Fortsetzen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-share-button.tsx:46
|
#: packages/ui/components/document/document-share-button.tsx:46
|
||||||
msgid "Copied to clipboard"
|
msgid "Copied to clipboard"
|
||||||
msgstr "In die Zwischenablage kopiert"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:360
|
#: packages/ui/primitives/document-flow/add-signature.tsx:360
|
||||||
msgid "Custom Text"
|
msgid "Custom Text"
|
||||||
msgstr "Benutzerdefinierter Text"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:840
|
#: packages/ui/primitives/document-flow/add-fields.tsx:840
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:684
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:240
|
#: packages/ui/primitives/document-flow/add-settings.tsx:271
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
|
||||||
msgid "Date Format"
|
msgid "Date Format"
|
||||||
msgstr "Datumsformat"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:570
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:570
|
||||||
msgid "Direct link receiver"
|
msgid "Direct link receiver"
|
||||||
msgstr "Empfänger des direkten Links"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:166
|
#: packages/ui/primitives/document-flow/add-settings.tsx:174
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
|
||||||
msgid "Document access"
|
msgid "Document access"
|
||||||
msgstr "Dokumentenzugriff"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:20
|
#: packages/lib/constants/template.ts:20
|
||||||
msgid "Document Creation"
|
msgid "Document Creation"
|
||||||
msgstr "Dokumenterstellung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-download-button.tsx:68
|
#: packages/ui/components/document/document-download-button.tsx:68
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
msgstr "Herunterladen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:162
|
#: packages/ui/primitives/document-dropzone.tsx:162
|
||||||
msgid "Drag & drop your PDF here."
|
msgid "Drag & drop your PDF here."
|
||||||
msgstr "Ziehen Sie Ihr PDF hierher."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:970
|
#: packages/ui/primitives/document-flow/add-fields.tsx:970
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:814
|
||||||
msgid "Dropdown"
|
msgid "Dropdown"
|
||||||
msgstr "Dropdown"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:148
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:148
|
||||||
msgid "Dropdown options"
|
msgid "Dropdown options"
|
||||||
msgstr "Dropdown-Optionen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:788
|
#: packages/ui/primitives/document-flow/add-fields.tsx:788
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:272
|
#: packages/ui/primitives/document-flow/add-signature.tsx:272
|
||||||
@@ -268,15 +268,15 @@ msgstr "Dropdown-Optionen"
|
|||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:463
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:470
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "E-Mail"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:184
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:184
|
||||||
msgid "Email Options"
|
msgid "Email Options"
|
||||||
msgstr "E-Mail-Optionen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:8
|
#: packages/lib/constants/template.ts:8
|
||||||
msgid "Enable Direct Link Signing"
|
msgid "Enable Direct Link Signing"
|
||||||
msgstr "Direktlink-Signierung aktivieren"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:392
|
#: packages/ui/primitives/document-flow/add-signers.tsx:392
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:362
|
||||||
@@ -285,44 +285,44 @@ msgstr ""
|
|||||||
|
|
||||||
#: packages/ui/primitives/document-password-dialog.tsx:84
|
#: packages/ui/primitives/document-password-dialog.tsx:84
|
||||||
msgid "Enter password"
|
msgid "Enter password"
|
||||||
msgstr "Passwort eingeben"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:216
|
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:216
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Fehler"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:210
|
#: packages/ui/primitives/document-flow/add-settings.tsx:241
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
|
||||||
msgid "External ID"
|
msgid "External ID"
|
||||||
msgstr "Externe ID"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:217
|
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:217
|
||||||
msgid "Failed to save settings."
|
msgid "Failed to save settings."
|
||||||
msgstr "Einstellungen konnten nicht gespeichert werden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:90
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:90
|
||||||
msgid "Field character limit"
|
msgid "Field character limit"
|
||||||
msgstr "Zeichenbeschränkung des Feldes"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:107
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:107
|
||||||
msgid "Field format"
|
msgid "Field format"
|
||||||
msgstr "Feldformat"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:50
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:50
|
||||||
msgid "Field label"
|
msgid "Field label"
|
||||||
msgstr "Feldbeschriftung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:62
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:62
|
||||||
msgid "Field placeholder"
|
msgid "Field placeholder"
|
||||||
msgstr "Feldplatzhalter"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:64
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:64
|
||||||
msgid "Global recipient action authentication"
|
msgid "Global recipient action authentication"
|
||||||
msgstr "Globale Empfängerauthentifizierung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/document-flow-root.tsx:142
|
#: packages/ui/primitives/document-flow/document-flow-root.tsx:142
|
||||||
msgid "Go Back"
|
msgid "Go Back"
|
||||||
msgstr "Zurück"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/signature-pad/signature-pad.tsx:297
|
#: packages/ui/primitives/signature-pad/signature-pad.tsx:297
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
@@ -330,55 +330,51 @@ msgstr ""
|
|||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:72
|
#: packages/lib/constants/recipient-roles.ts:72
|
||||||
msgid "I am a signer of this document"
|
msgid "I am a signer of this document"
|
||||||
msgstr "Ich bin ein Unterzeichner dieses Dokuments"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:75
|
#: packages/lib/constants/recipient-roles.ts:75
|
||||||
msgid "I am a viewer of this document"
|
msgid "I am a viewer of this document"
|
||||||
msgstr "Ich bin ein Betrachter dieses Dokuments"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:73
|
#: packages/lib/constants/recipient-roles.ts:73
|
||||||
msgid "I am an approver of this document"
|
msgid "I am an approver of this document"
|
||||||
msgstr "Ich bin ein Genehmiger dieses Dokuments"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:74
|
#: packages/lib/constants/recipient-roles.ts:74
|
||||||
msgid "I am required to receive a copy of this document"
|
msgid "I am required to receive a copy of this document"
|
||||||
msgstr "Ich bin verpflichtet, eine Kopie dieses Dokuments zu erhalten"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:74
|
|
||||||
#~ msgid "I am required to recieve a copy of this document"
|
|
||||||
#~ msgstr "I am required to recieve a copy of this document"
|
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:29
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:29
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:87
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:87
|
||||||
msgid "Inherit authentication method"
|
msgid "Inherit authentication method"
|
||||||
msgstr "Authentifizierungsmethode erben"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:64
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:64
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:69
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:69
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:45
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:45
|
||||||
msgid "Label"
|
msgid "Label"
|
||||||
msgstr "Beschriftung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/teams.ts:11
|
#: packages/lib/constants/teams.ts:11
|
||||||
msgid "Manager"
|
msgid "Manager"
|
||||||
msgstr "Manager"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:168
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:168
|
||||||
msgid "Max"
|
msgid "Max"
|
||||||
msgstr "Max"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/teams.ts:12
|
#: packages/lib/constants/teams.ts:12
|
||||||
msgid "Member"
|
msgid "Member"
|
||||||
msgstr "Mitglied"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-subject.tsx:95
|
#: packages/ui/primitives/document-flow/add-subject.tsx:95
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:215
|
||||||
msgid "Message <0>(Optional)</0>"
|
msgid "Message <0>(Optional)</0>"
|
||||||
msgstr "Nachricht <0>(Optional)</0>"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:156
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:156
|
||||||
msgid "Min"
|
msgid "Min"
|
||||||
msgstr "Min"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:814
|
#: packages/ui/primitives/document-flow/add-fields.tsx:814
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:298
|
#: packages/ui/primitives/document-flow/add-signature.tsx:298
|
||||||
@@ -388,93 +384,93 @@ msgstr "Min"
|
|||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:498
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:504
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:52
|
#: packages/ui/components/recipient/recipient-role-select.tsx:52
|
||||||
msgid "Needs to approve"
|
msgid "Needs to approve"
|
||||||
msgstr "Muss genehmigen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:31
|
#: packages/ui/components/recipient/recipient-role-select.tsx:31
|
||||||
msgid "Needs to sign"
|
msgid "Needs to sign"
|
||||||
msgstr "Muss unterzeichnen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:73
|
#: packages/ui/components/recipient/recipient-role-select.tsx:73
|
||||||
msgid "Needs to view"
|
msgid "Needs to view"
|
||||||
msgstr "Muss sehen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:625
|
#: packages/ui/primitives/document-flow/add-fields.tsx:625
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:497
|
||||||
msgid "No recipient matching this description was found."
|
msgid "No recipient matching this description was found."
|
||||||
msgstr "Kein passender Empfänger mit dieser Beschreibung gefunden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:641
|
#: packages/ui/primitives/document-flow/add-fields.tsx:641
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:513
|
||||||
msgid "No recipients with this role"
|
msgid "No recipients with this role"
|
||||||
msgstr "Keine Empfänger mit dieser Rolle"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:30
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:30
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:43
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:43
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:31
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:31
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:46
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:46
|
||||||
msgid "No restrictions"
|
msgid "No restrictions"
|
||||||
msgstr "Keine Einschränkungen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table.tsx:148
|
#: packages/ui/primitives/data-table.tsx:148
|
||||||
msgid "No results found"
|
msgid "No results found"
|
||||||
msgstr "Keine Ergebnisse gefunden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:30
|
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:30
|
||||||
msgid "No signature field found"
|
msgid "No signature field found"
|
||||||
msgstr "Kein Unterschriftsfeld gefunden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/combobox.tsx:60
|
#: packages/ui/primitives/combobox.tsx:60
|
||||||
#: packages/ui/primitives/multi-select-combobox.tsx:153
|
#: packages/ui/primitives/multi-select-combobox.tsx:153
|
||||||
msgid "No value found."
|
msgid "No value found."
|
||||||
msgstr "Kein Wert gefunden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:892
|
#: packages/ui/primitives/document-flow/add-fields.tsx:892
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:736
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Nummer"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:100
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:100
|
||||||
msgid "Number format"
|
msgid "Number format"
|
||||||
msgstr "Zahlenformat"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:9
|
#: packages/lib/constants/template.ts:9
|
||||||
msgid "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
|
msgid "Once enabled, you can select any active recipient to be a direct link signing recipient, or create a new one. This recipient type cannot be edited or deleted."
|
||||||
msgstr "Sobald aktiviert, können Sie einen aktiven Empfänger für die Direktlink-Signierung auswählen oder einen neuen erstellen. Dieser Empfängertyp kann nicht bearbeitet oder gelöscht werden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:17
|
#: packages/lib/constants/template.ts:17
|
||||||
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."
|
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."
|
||||||
msgstr "Sobald Ihre Vorlage eingerichtet ist, teilen Sie den Link überall, wo Sie möchten. Die Person, die den Link öffnet, kann ihre Informationen im Feld für direkte Empfänger eingeben und alle anderen ihr zugewiesenen Felder ausfüllen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table-pagination.tsx:77
|
#: packages/ui/primitives/data-table-pagination.tsx:77
|
||||||
msgid "Page {0} of {1}"
|
msgid "Page {0} of {1}"
|
||||||
msgstr "Seite {0} von {1}"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-password-dialog.tsx:62
|
#: packages/ui/primitives/document-password-dialog.tsx:62
|
||||||
msgid "Password Required"
|
msgid "Password Required"
|
||||||
msgstr "Passwort erforderlich"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:154
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:154
|
||||||
msgid "Pick a number"
|
msgid "Pick a number"
|
||||||
msgstr "Wählen Sie eine Zahl"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:76
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:76
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:81
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:81
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:57
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:57
|
||||||
msgid "Placeholder"
|
msgid "Placeholder"
|
||||||
msgstr "Platzhalter"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:918
|
#: packages/ui/primitives/document-flow/add-fields.tsx:918
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:762
|
||||||
msgid "Radio"
|
msgid "Radio"
|
||||||
msgstr "Radio"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:133
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:133
|
||||||
msgid "Radio values"
|
msgid "Radio values"
|
||||||
msgstr "Radio-Werte"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:184
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:184
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:137
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:137
|
||||||
@@ -482,30 +478,30 @@ msgstr "Radio-Werte"
|
|||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:122
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:122
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:114
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:114
|
||||||
msgid "Read only"
|
msgid "Read only"
|
||||||
msgstr "Nur lesen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:95
|
#: packages/ui/components/recipient/recipient-role-select.tsx:95
|
||||||
msgid "Receives copy"
|
msgid "Receives copy"
|
||||||
msgstr "Erhält Kopie"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:184
|
#: packages/ui/primitives/document-flow/add-settings.tsx:215
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
|
||||||
msgid "Recipient action authentication"
|
msgid "Recipient action authentication"
|
||||||
msgstr "Empfängeraktion Authentifizierung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/signature-pad/signature-pad.tsx:283
|
#: packages/ui/primitives/signature-pad/signature-pad.tsx:283
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:298
|
#: packages/ui/primitives/document-flow/add-settings.tsx:329
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
|
||||||
msgid "Redirect URL"
|
msgid "Redirect URL"
|
||||||
msgstr "Weiterleitungs-URL"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:1008
|
#: packages/ui/primitives/document-flow/add-fields.tsx:1008
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "Entfernen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:174
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:174
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:127
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:127
|
||||||
@@ -513,268 +509,264 @@ msgstr "Entfernen"
|
|||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:112
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/radio-field.tsx:112
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:104
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx:104
|
||||||
msgid "Required field"
|
msgid "Required field"
|
||||||
msgstr "Pflichtfeld"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table-pagination.tsx:55
|
#: packages/ui/primitives/data-table-pagination.tsx:55
|
||||||
msgid "Rows per page"
|
msgid "Rows per page"
|
||||||
msgstr "Zeilen pro Seite"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:286
|
#: packages/ui/primitives/document-flow/field-item-advanced-settings.tsx:286
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:848
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:848
|
||||||
msgid "Save Template"
|
msgid "Save Template"
|
||||||
msgstr "Vorlage speichern"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/common/language-switcher-dialog.tsx:34
|
#: packages/ui/components/common/language-switcher-dialog.tsx:34
|
||||||
msgid "Search languages..."
|
msgid "Search languages..."
|
||||||
msgstr "Sprachen suchen..."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:105
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr "Auswählen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/combobox.tsx:38
|
#: packages/ui/primitives/combobox.tsx:38
|
||||||
msgid "Select an option"
|
msgid "Select an option"
|
||||||
msgstr "Option auswählen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:137
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:137
|
||||||
msgid "Select at least"
|
msgid "Select at least"
|
||||||
msgstr "Wählen Sie mindestens"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:95
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/dropdown-field.tsx:95
|
||||||
msgid "Select default option"
|
msgid "Select default option"
|
||||||
msgstr "Standardoption auswählen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
|
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:34
|
||||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
|
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:64
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Senden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:41
|
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:41
|
||||||
msgid "Send Document"
|
msgid "Send Document"
|
||||||
msgstr "Dokument senden"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-share-button.tsx:135
|
#: packages/ui/components/document/document-share-button.tsx:135
|
||||||
msgid "Share Signature Card"
|
msgid "Share Signature Card"
|
||||||
msgstr "Unterschriftenkarte teilen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:16
|
#: packages/lib/constants/template.ts:16
|
||||||
msgid "Share the Link"
|
msgid "Share the Link"
|
||||||
msgstr "Link teilen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:671
|
#: packages/ui/primitives/document-flow/add-signers.tsx:671
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:655
|
||||||
msgid "Show advanced settings"
|
msgid "Show advanced settings"
|
||||||
msgstr "Erweiterte Einstellungen anzeigen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:20
|
#: packages/lib/constants/recipient-roles.ts:20
|
||||||
msgid "Sign"
|
msgid "Sign"
|
||||||
msgstr "Unterschreiben"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:736
|
#: packages/ui/primitives/document-flow/add-fields.tsx:736
|
||||||
#: packages/ui/primitives/document-flow/add-signature.tsx:323
|
#: packages/ui/primitives/document-flow/add-signature.tsx:323
|
||||||
#: packages/ui/primitives/document-flow/field-icon.tsx:52
|
#: packages/ui/primitives/document-flow/field-icon.tsx:52
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:580
|
||||||
msgid "Signature"
|
msgid "Signature"
|
||||||
msgstr "Unterschrift"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:21
|
#: packages/lib/constants/recipient-roles.ts:21
|
||||||
msgid "Signed"
|
msgid "Signed"
|
||||||
msgstr "Unterzeichnet"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:23
|
#: packages/lib/constants/recipient-roles.ts:23
|
||||||
msgid "Signer"
|
msgid "Signer"
|
||||||
msgstr "Unterzeichner"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:22
|
#: packages/lib/constants/recipient-roles.ts:22
|
||||||
msgid "Signing"
|
msgid "Signing"
|
||||||
msgstr "Unterzeichnung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:34
|
#: packages/ui/primitives/document-flow/missing-signature-field-dialog.tsx:34
|
||||||
msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
|
msgid "Some signers have not been assigned a signature field. Please assign at least 1 signature field to each signer before proceeding."
|
||||||
msgstr "Einige Unterzeichner haben noch kein Unterschriftsfeld zugewiesen bekommen. Bitte weisen Sie jedem Unterzeichner mindestens ein Unterschriftsfeld zu, bevor Sie fortfahren."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-share-button.tsx:51
|
#: packages/ui/components/document/document-share-button.tsx:51
|
||||||
msgid "Something went wrong"
|
msgid "Something went wrong"
|
||||||
msgstr "Etwas ist schief gelaufen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/data-table.tsx:136
|
#: packages/ui/primitives/data-table.tsx:136
|
||||||
msgid "Something went wrong."
|
msgid "Something went wrong."
|
||||||
msgstr "Etwas ist schief gelaufen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/document-flow-root.tsx:107
|
#: packages/ui/primitives/document-flow/document-flow-root.tsx:107
|
||||||
msgid "Step <0>{step} of {maxStep}</0>"
|
msgid "Step <0>{step} of {maxStep}</0>"
|
||||||
msgstr "Schritt <0>{step} von {maxStep}</0>"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-subject.tsx:78
|
#: packages/ui/primitives/document-flow/add-subject.tsx:78
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:195
|
||||||
msgid "Subject <0>(Optional)</0>"
|
msgid "Subject <0>(Optional)</0>"
|
||||||
msgstr "Betreff <0>(Optional)</0>"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-password-dialog.tsx:97
|
#: packages/ui/primitives/document-password-dialog.tsx:97
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr "Einreichen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:134
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:134
|
||||||
msgid "Template title"
|
msgid "Template title"
|
||||||
msgstr "Vorlagentitel"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:866
|
#: packages/ui/primitives/document-flow/add-fields.tsx:866
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:710
|
||||||
msgid "Text"
|
msgid "Text"
|
||||||
msgstr "Text"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:44
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:44
|
||||||
msgid "The authentication required for recipients to sign fields"
|
msgid "The authentication required for recipients to sign fields"
|
||||||
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger Felder signieren"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:68
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:68
|
||||||
msgid "The authentication required for recipients to sign the signature field."
|
msgid "The authentication required for recipients to sign the signature field."
|
||||||
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger das Signaturfeld signieren können."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:67
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:67
|
||||||
msgid "The authentication required for recipients to view the document."
|
msgid "The authentication required for recipients to view the document."
|
||||||
msgstr "Die Authentifizierung, die erforderlich ist, damit Empfänger das Dokument anzeigen können."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-send-email-message-helper.tsx:31
|
#: packages/ui/components/document/document-send-email-message-helper.tsx:31
|
||||||
msgid "The document's name"
|
msgid "The document's name"
|
||||||
msgstr "Der Name des Dokuments"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-password-dialog.tsx:52
|
#: packages/ui/primitives/document-password-dialog.tsx:52
|
||||||
msgid "The password you have entered is incorrect. Please try again."
|
msgid "The password you have entered is incorrect. Please try again."
|
||||||
msgstr "Das eingegebene Passwort ist falsch. Bitte versuchen Sie es erneut."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:103
|
#: packages/ui/components/recipient/recipient-role-select.tsx:103
|
||||||
msgid "The recipient is not required to take any action and receives a copy of the document after it is completed."
|
msgid "The recipient is not required to take any action and receives a copy of the document after it is completed."
|
||||||
msgstr "Der Empfänger muss keine Aktion ausführen und erhält nach Abschluss eine Kopie des Dokuments."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:60
|
#: packages/ui/components/recipient/recipient-role-select.tsx:60
|
||||||
msgid "The recipient is required to approve the document for it to be completed."
|
msgid "The recipient is required to approve the document for it to be completed."
|
||||||
msgstr "Der Empfänger muss das Dokument genehmigen, damit es abgeschlossen werden kann."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:39
|
#: packages/ui/components/recipient/recipient-role-select.tsx:39
|
||||||
msgid "The recipient is required to sign the document for it to be completed."
|
msgid "The recipient is required to sign the document for it to be completed."
|
||||||
msgstr "Der Empfänger muss das Dokument unterschreiben, damit es abgeschlossen werden kann."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-role-select.tsx:81
|
#: packages/ui/components/recipient/recipient-role-select.tsx:81
|
||||||
msgid "The recipient is required to view the document for it to be completed."
|
msgid "The recipient is required to view the document for it to be completed."
|
||||||
msgstr "Der Empfänger muss das Dokument anzeigen, damit es abgeschlossen werden kann."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-share-button.tsx:52
|
#: packages/ui/components/document/document-share-button.tsx:52
|
||||||
msgid "The sharing link could not be created at this time. Please try again."
|
msgid "The sharing link could not be created at this time. Please try again."
|
||||||
msgstr "Der Freigabelink konnte in diesem Moment nicht erstellt werden. Bitte versuchen Sie es erneut."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-share-button.tsx:47
|
#: packages/ui/components/document/document-share-button.tsx:47
|
||||||
msgid "The sharing link has been copied to your clipboard."
|
msgid "The sharing link has been copied to your clipboard."
|
||||||
msgstr "Der Freigabelink wurde in Ihre Zwischenablage kopiert."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-send-email-message-helper.tsx:25
|
#: packages/ui/components/document/document-send-email-message-helper.tsx:25
|
||||||
msgid "The signer's email"
|
msgid "The signer's email"
|
||||||
msgstr "Die E-Mail des Unterzeichners"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-send-email-message-helper.tsx:19
|
#: packages/ui/components/document/document-send-email-message-helper.tsx:19
|
||||||
msgid "The signer's name"
|
msgid "The signer's name"
|
||||||
msgstr "Der Name des Unterzeichners"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-action-select.tsx:72
|
#: packages/ui/components/document/document-global-auth-action-select.tsx:72
|
||||||
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
|
msgid "This can be overriden by setting the authentication requirements directly on each recipient in the next step."
|
||||||
msgstr "Dies kann überschrieben werden, indem die Authentifizierungsanforderungen im nächsten Schritt direkt für jeden Empfänger festgelegt werden."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:697
|
#: packages/ui/primitives/document-flow/add-fields.tsx:697
|
||||||
msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
|
msgid "This document has already been sent to this recipient. You can no longer edit this recipient."
|
||||||
msgstr "Dieses Dokument wurde bereits an diesen Empfänger gesendet. Sie können diesen Empfänger nicht mehr bearbeiten."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-password-dialog.tsx:66
|
#: packages/ui/primitives/document-password-dialog.tsx:66
|
||||||
msgid "This document is password protected. Please enter the password to view the document."
|
msgid "This document is password protected. Please enter the password to view the document."
|
||||||
msgstr "Dieses Dokument ist durch ein Passwort geschützt. Bitte geben Sie das Passwort ein, um das Dokument anzusehen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:573
|
#: packages/ui/primitives/template-flow/add-template-placeholder-recipients.tsx:573
|
||||||
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
|
msgid "This field cannot be modified or deleted. When you share this template's direct link or add it to your public profile, anyone who accesses it can input their name and email, and fill in the fields assigned to them."
|
||||||
msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den direkten Link dieser Vorlage teilen oder zu Ihrem öffentlichen Profil hinzufügen, kann jeder, der darauf zugreift, seinen Namen und seine E-Mail-Adresse eingeben und die ihm zugewiesenen Felder ausfüllen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-signers.tsx:195
|
#: packages/ui/primitives/document-flow/add-signers.tsx:195
|
||||||
msgid "This signer has already received the document."
|
msgid "This signer has already received the document."
|
||||||
msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
||||||
msgid "This will override any global settings."
|
msgid "This will override any global settings."
|
||||||
msgstr "Dies überschreibt alle globalen Einstellungen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:274
|
#: packages/ui/primitives/document-flow/add-settings.tsx:305
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
|
||||||
msgid "Time Zone"
|
msgid "Time Zone"
|
||||||
msgstr "Zeitzone"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:145
|
#: packages/ui/primitives/document-flow/add-settings.tsx:153
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Titel"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-fields.tsx:983
|
#: packages/ui/primitives/document-flow/add-fields.tsx:983
|
||||||
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828
|
#: packages/ui/primitives/template-flow/add-template-fields.tsx:828
|
||||||
msgid "To proceed further, please set at least one value for the {0} field."
|
msgid "To proceed further, please set at least one value for the {0} field."
|
||||||
msgstr "Um fortzufahren, legen Sie bitte mindestens einen Wert für das Feld {0} fest."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
#: packages/ui/primitives/document-flow/add-subject.tsx:124
|
||||||
msgid "Update"
|
msgid "Update"
|
||||||
msgstr "Aktualisieren"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/template.ts:13
|
#: packages/lib/constants/template.ts:13
|
||||||
msgid "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
|
msgid "Update the role and add fields as required for the direct recipient. The individual who uses the direct link will sign the document as the direct recipient."
|
||||||
msgstr "Aktualisieren Sie die Rolle und fügen Sie Felder nach Bedarf für den direkten Empfänger hinzu. Die Person, die den direkten Link verwendet, wird das Dokument als direkter Empfänger unterzeichnen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:168
|
#: packages/ui/primitives/document-dropzone.tsx:168
|
||||||
msgid "Upgrade"
|
msgid "Upgrade"
|
||||||
msgstr "Upgrade"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:70
|
#: packages/ui/primitives/document-dropzone.tsx:70
|
||||||
msgid "Upload Template Document"
|
msgid "Upload Template Document"
|
||||||
msgstr "Vorlagendokument hochladen"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:130
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx:130
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:147
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:147
|
||||||
msgid "Validation"
|
msgid "Validation"
|
||||||
msgstr "Validierung"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:88
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:88
|
||||||
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:93
|
#: packages/ui/primitives/document-flow/field-items-advanced-settings/number-field.tsx:93
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr "Wert"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:26
|
#: packages/lib/constants/recipient-roles.ts:26
|
||||||
msgid "View"
|
msgid "View"
|
||||||
msgstr "View"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:27
|
#: packages/lib/constants/recipient-roles.ts:27
|
||||||
msgid "Viewed"
|
msgid "Viewed"
|
||||||
msgstr "Viewed"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:29
|
#: packages/lib/constants/recipient-roles.ts:29
|
||||||
msgid "Viewer"
|
msgid "Viewer"
|
||||||
msgstr "Viewer"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/lib/constants/recipient-roles.ts:28
|
#: packages/lib/constants/recipient-roles.ts:28
|
||||||
msgid "Viewing"
|
msgid "Viewing"
|
||||||
msgstr "Viewing"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/signature-pad/signature-pad.tsx:280
|
|
||||||
#~ msgid "White"
|
|
||||||
#~ msgstr ""
|
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:44
|
#: packages/ui/primitives/document-flow/send-document-action-dialog.tsx:44
|
||||||
msgid "You are about to send this document to the recipients. Are you sure you want to continue?"
|
msgid "You are about to send this document to the recipients. Are you sure you want to continue?"
|
||||||
msgstr "Sie sind dabei, dieses Dokument an die Empfänger zu senden. Sind Sie sicher, dass Sie fortfahren möchten?"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/components/document/document-send-email-message-helper.tsx:11
|
#: packages/ui/components/document/document-send-email-message-helper.tsx:11
|
||||||
msgid "You can use the following variables in your message:"
|
msgid "You can use the following variables in your message:"
|
||||||
msgstr "Sie können die folgenden Variablen in Ihrer Nachricht verwenden:"
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:43
|
#: packages/ui/primitives/document-dropzone.tsx:43
|
||||||
msgid "You cannot upload documents at this time."
|
msgid "You cannot upload documents at this time."
|
||||||
msgstr "Sie können derzeit keine Dokumente hochladen."
|
msgstr ""
|
||||||
|
|
||||||
#: packages/ui/primitives/document-dropzone.tsx:69
|
#: packages/ui/primitives/document-dropzone.tsx:69
|
||||||
msgid "You have reached your document limit."
|
msgid "You have reached your document limit."
|
||||||
msgstr "Sie haben Ihr Dokumentenlimit erreicht."
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -55,12 +55,12 @@ msgstr "<0>Require passkey</0> - The recipient must have an account and passkey
|
|||||||
msgid "Add a document"
|
msgid "Add a document"
|
||||||
msgstr "Add a document"
|
msgstr "Add a document"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:305
|
#: packages/ui/primitives/document-flow/add-settings.tsx:336
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:339
|
||||||
msgid "Add a URL to redirect the user to once the document is signed"
|
msgid "Add a URL to redirect the user to once the document is signed"
|
||||||
msgstr "Add a URL to redirect the user to once the document is signed"
|
msgstr "Add a URL to redirect the user to once the document is signed"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:217
|
#: packages/ui/primitives/document-flow/add-settings.tsx:248
|
||||||
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
|
msgid "Add an external ID to the document. This can be used to identify the document in external systems."
|
||||||
msgstr "Add an external ID to the document. This can be used to identify the document in external systems."
|
msgstr "Add an external ID to the document. This can be used to identify the document in external systems."
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ msgstr "Add text to the field"
|
|||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Admin"
|
msgstr "Admin"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:199
|
#: packages/ui/primitives/document-flow/add-settings.tsx:230
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:238
|
||||||
msgid "Advanced Options"
|
msgid "Advanced Options"
|
||||||
msgstr "Advanced Options"
|
msgstr "Advanced Options"
|
||||||
@@ -220,7 +220,7 @@ msgstr "Custom Text"
|
|||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Date"
|
msgstr "Date"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:240
|
#: packages/ui/primitives/document-flow/add-settings.tsx:271
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:279
|
||||||
msgid "Date Format"
|
msgid "Date Format"
|
||||||
msgstr "Date Format"
|
msgstr "Date Format"
|
||||||
@@ -230,7 +230,7 @@ msgid "Direct link receiver"
|
|||||||
msgstr "Direct link receiver"
|
msgstr "Direct link receiver"
|
||||||
|
|
||||||
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
|
#: packages/ui/components/document/document-global-auth-access-select.tsx:62
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:166
|
#: packages/ui/primitives/document-flow/add-settings.tsx:174
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:151
|
||||||
msgid "Document access"
|
msgid "Document access"
|
||||||
msgstr "Document access"
|
msgstr "Document access"
|
||||||
@@ -286,7 +286,7 @@ msgstr "Enter password"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:210
|
#: packages/ui/primitives/document-flow/add-settings.tsx:241
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:249
|
||||||
msgid "External ID"
|
msgid "External ID"
|
||||||
msgstr "External ID"
|
msgstr "External ID"
|
||||||
@@ -484,7 +484,7 @@ msgid "Receives copy"
|
|||||||
msgstr "Receives copy"
|
msgstr "Receives copy"
|
||||||
|
|
||||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
|
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:39
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:184
|
#: packages/ui/primitives/document-flow/add-settings.tsx:215
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:169
|
||||||
msgid "Recipient action authentication"
|
msgid "Recipient action authentication"
|
||||||
msgstr "Recipient action authentication"
|
msgstr "Recipient action authentication"
|
||||||
@@ -493,7 +493,7 @@ msgstr "Recipient action authentication"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "Red"
|
msgstr "Red"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:298
|
#: packages/ui/primitives/document-flow/add-settings.tsx:329
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:332
|
||||||
msgid "Redirect URL"
|
msgid "Redirect URL"
|
||||||
msgstr "Redirect URL"
|
msgstr "Redirect URL"
|
||||||
@@ -698,12 +698,12 @@ msgstr "This signer has already received the document."
|
|||||||
msgid "This will override any global settings."
|
msgid "This will override any global settings."
|
||||||
msgstr "This will override any global settings."
|
msgstr "This will override any global settings."
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:274
|
#: packages/ui/primitives/document-flow/add-settings.tsx:305
|
||||||
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
|
#: packages/ui/primitives/template-flow/add-template-settings.tsx:309
|
||||||
msgid "Time Zone"
|
msgid "Time Zone"
|
||||||
msgstr "Time Zone"
|
msgstr "Time Zone"
|
||||||
|
|
||||||
#: packages/ui/primitives/document-flow/add-settings.tsx:145
|
#: packages/ui/primitives/document-flow/add-settings.tsx:153
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Title"
|
msgstr "Title"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -55,11 +55,11 @@ msgstr "{0, plural, one {# Seat} other {# Seats}}"
|
|||||||
msgid "{0, plural, one {<0>You have <1>1</1> pending team invitation</0>} other {<2>You have <3>#</3> pending team invitations</2>}}"
|
msgid "{0, plural, one {<0>You have <1>1</1> pending team invitation</0>} other {<2>You have <3>#</3> pending team invitations</2>}}"
|
||||||
msgstr "{0, plural, one {<0>You have <1>1</1> pending team invitation</0>} other {<2>You have <3>#</3> pending team invitations</2>}}"
|
msgstr "{0, plural, one {<0>You have <1>1</1> pending team invitation</0>} other {<2>You have <3>#</3> pending team invitations</2>}}"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit/document-edit-page-view.tsx:102
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit/document-edit-page-view.tsx:129
|
||||||
msgid "{0, plural, one {1 Recipient} other {# Recipients}}"
|
msgid "{0, plural, one {1 Recipient} other {# Recipients}}"
|
||||||
msgstr "{0, plural, one {1 Recipient} other {# Recipients}}"
|
msgstr "{0, plural, one {1 Recipient} other {# Recipients}}"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:204
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:230
|
||||||
msgid "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
msgid "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
||||||
msgstr "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
msgstr "{0, plural, one {Waiting on 1 recipient} other {Waiting on # recipients}}"
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ msgstr "{0} document"
|
|||||||
msgid "{0} of {1} documents remaining this month."
|
msgid "{0} of {1} documents remaining this month."
|
||||||
msgstr "{0} of {1} documents remaining this month."
|
msgstr "{0} of {1} documents remaining this month."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:139
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:165
|
||||||
msgid "{0} Recipient(s)"
|
msgid "{0} Recipient(s)"
|
||||||
msgstr "{0} Recipient(s)"
|
msgstr "{0} Recipient(s)"
|
||||||
|
|
||||||
@@ -365,13 +365,13 @@ msgstr "An email requesting the transfer of this team has been sent."
|
|||||||
msgid "An error occurred"
|
msgid "An error occurred"
|
||||||
msgstr "An error occurred"
|
msgstr "An error occurred"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:247
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:248
|
||||||
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:197
|
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:197
|
||||||
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:231
|
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:231
|
||||||
msgid "An error occurred while adding signers."
|
msgid "An error occurred while adding signers."
|
||||||
msgstr "An error occurred while adding signers."
|
msgstr "An error occurred while adding signers."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:277
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:278
|
||||||
msgid "An error occurred while adding the fields."
|
msgid "An error occurred while adding the fields."
|
||||||
msgstr "An error occurred while adding the fields."
|
msgstr "An error occurred while adding the fields."
|
||||||
|
|
||||||
@@ -429,7 +429,7 @@ msgstr "An error occurred while removing the signature."
|
|||||||
msgid "An error occurred while removing the text."
|
msgid "An error occurred while removing the text."
|
||||||
msgstr "An error occurred while removing the text."
|
msgstr "An error occurred while removing the text."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:308
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:309
|
||||||
msgid "An error occurred while sending the document."
|
msgid "An error occurred while sending the document."
|
||||||
msgstr "An error occurred while sending the document."
|
msgstr "An error occurred while sending the document."
|
||||||
|
|
||||||
@@ -453,7 +453,7 @@ msgstr "An error occurred while signing the document."
|
|||||||
msgid "An error occurred while trying to create a checkout session."
|
msgid "An error occurred while trying to create a checkout session."
|
||||||
msgstr "An error occurred while trying to create a checkout session."
|
msgstr "An error occurred while trying to create a checkout session."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:213
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:214
|
||||||
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:166
|
#: apps/web/src/app/(dashboard)/templates/[id]/edit-template.tsx:166
|
||||||
msgid "An error occurred while updating the document settings."
|
msgid "An error occurred while updating the document settings."
|
||||||
msgstr "An error occurred while updating the document settings."
|
msgstr "An error occurred while updating the document settings."
|
||||||
@@ -1215,7 +1215,7 @@ msgid "Document created"
|
|||||||
msgstr "Document created"
|
msgstr "Document created"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/super-delete-document-dialog.tsx:51
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/super-delete-document-dialog.tsx:51
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:147
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:173
|
||||||
#: apps/web/src/app/(dashboard)/documents/delete-document-dialog.tsx:59
|
#: apps/web/src/app/(dashboard)/documents/delete-document-dialog.tsx:59
|
||||||
msgid "Document deleted"
|
msgid "Document deleted"
|
||||||
msgstr "Document deleted"
|
msgstr "Document deleted"
|
||||||
@@ -1228,7 +1228,7 @@ msgstr "Document draft"
|
|||||||
msgid "Document Duplicated"
|
msgid "Document Duplicated"
|
||||||
msgstr "Document Duplicated"
|
msgstr "Document Duplicated"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:158
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:184
|
||||||
#: apps/web/src/components/document/document-history-sheet.tsx:104
|
#: apps/web/src/components/document/document-history-sheet.tsx:104
|
||||||
msgid "Document history"
|
msgid "Document history"
|
||||||
msgstr "Document history"
|
msgstr "Document history"
|
||||||
@@ -1269,7 +1269,7 @@ msgstr "Document re-sent"
|
|||||||
msgid "Document resealed"
|
msgid "Document resealed"
|
||||||
msgstr "Document resealed"
|
msgstr "Document resealed"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:297
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:298
|
||||||
msgid "Document sent"
|
msgid "Document sent"
|
||||||
msgstr "Document sent"
|
msgstr "Document sent"
|
||||||
|
|
||||||
@@ -1307,11 +1307,11 @@ msgstr "Document will be permanently deleted"
|
|||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/nav.tsx:65
|
#: apps/web/src/app/(dashboard)/admin/nav.tsx:65
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:92
|
#: apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx:92
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:113
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:139
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit/document-edit-page-view.tsx:82
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit/document-edit-page-view.tsx:109
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/loading.tsx:16
|
#: apps/web/src/app/(dashboard)/documents/[id]/loading.tsx:16
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/sent/page.tsx:15
|
#: apps/web/src/app/(dashboard)/documents/[id]/sent/page.tsx:15
|
||||||
#: apps/web/src/app/(dashboard)/documents/documents-page-view.tsx:110
|
#: apps/web/src/app/(dashboard)/documents/documents-page-view.tsx:114
|
||||||
#: apps/web/src/app/(profile)/p/[url]/page.tsx:166
|
#: apps/web/src/app/(profile)/p/[url]/page.tsx:166
|
||||||
#: apps/web/src/app/not-found.tsx:21
|
#: apps/web/src/app/not-found.tsx:21
|
||||||
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:205
|
#: apps/web/src/components/(dashboard)/common/command-menu.tsx:205
|
||||||
@@ -1486,10 +1486,10 @@ msgstr "Enter your text here"
|
|||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/admin/documents/[id]/admin-actions.tsx:41
|
#: apps/web/src/app/(dashboard)/admin/documents/[id]/admin-actions.tsx:41
|
||||||
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:78
|
#: apps/web/src/app/(dashboard)/admin/users/[id]/page.tsx:78
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:212
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:213
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:246
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:247
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:276
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:277
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:307
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:308
|
||||||
#: apps/web/src/app/(dashboard)/documents/move-document-dialog.tsx:57
|
#: apps/web/src/app/(dashboard)/documents/move-document-dialog.tsx:57
|
||||||
#: apps/web/src/app/(dashboard)/documents/upload-document.tsx:106
|
#: apps/web/src/app/(dashboard)/documents/upload-document.tsx:106
|
||||||
#: apps/web/src/app/(dashboard)/documents/upload-document.tsx:112
|
#: apps/web/src/app/(dashboard)/documents/upload-document.tsx:112
|
||||||
@@ -3313,11 +3313,11 @@ msgstr "This document has been cancelled by the owner and is no longer available
|
|||||||
msgid "This document has been cancelled by the owner."
|
msgid "This document has been cancelled by the owner."
|
||||||
msgstr "This document has been cancelled by the owner."
|
msgstr "This document has been cancelled by the owner."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:193
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:219
|
||||||
msgid "This document has been signed by all recipients"
|
msgid "This document has been signed by all recipients"
|
||||||
msgstr "This document has been signed by all recipients"
|
msgstr "This document has been signed by all recipients"
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:196
|
#: apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx:222
|
||||||
msgid "This document is currently a draft and has not been sent"
|
msgid "This document is currently a draft and has not been sent"
|
||||||
msgstr "This document is currently a draft and has not been sent"
|
msgstr "This document is currently a draft and has not been sent"
|
||||||
|
|
||||||
@@ -4368,7 +4368,7 @@ msgstr "Your document has been created from the template successfully."
|
|||||||
msgid "Your document has been re-sent successfully."
|
msgid "Your document has been re-sent successfully."
|
||||||
msgstr "Your document has been re-sent successfully."
|
msgstr "Your document has been re-sent successfully."
|
||||||
|
|
||||||
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:298
|
#: apps/web/src/app/(dashboard)/documents/[id]/edit-document.tsx:299
|
||||||
msgid "Your document has been sent successfully."
|
msgid "Your document has been sent successfully."
|
||||||
msgstr "Your document has been sent successfully."
|
msgstr "Your document has been sent successfully."
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const ZDocumentAuditLogTypeSchema = z.enum([
|
|||||||
'DOCUMENT_DELETED', // When the document is soft deleted.
|
'DOCUMENT_DELETED', // When the document is soft deleted.
|
||||||
'DOCUMENT_FIELD_INSERTED', // When a field is inserted (signed/approved/etc) by a recipient.
|
'DOCUMENT_FIELD_INSERTED', // When a field is inserted (signed/approved/etc) by a recipient.
|
||||||
'DOCUMENT_FIELD_UNINSERTED', // When a field is uninserted by a recipient.
|
'DOCUMENT_FIELD_UNINSERTED', // When a field is uninserted by a recipient.
|
||||||
|
'DOCUMENT_VISIBILITY_UPDATED', // When the document visibility scope is updated
|
||||||
'DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED', // When the global access authentication is updated.
|
'DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED', // When the global access authentication is updated.
|
||||||
'DOCUMENT_GLOBAL_AUTH_ACTION_UPDATED', // When the global action authentication is updated.
|
'DOCUMENT_GLOBAL_AUTH_ACTION_UPDATED', // When the global action authentication is updated.
|
||||||
'DOCUMENT_META_UPDATED', // When the document meta data is updated.
|
'DOCUMENT_META_UPDATED', // When the document meta data is updated.
|
||||||
@@ -311,6 +312,11 @@ export const ZDocumentAuditLogEventDocumentFieldUninsertedSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const ZDocumentAuditLogEventDocumentVisibilitySchema = z.object({
|
||||||
|
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED),
|
||||||
|
data: ZGenericFromToSchema,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event: Document global authentication access updated.
|
* Event: Document global authentication access updated.
|
||||||
*/
|
*/
|
||||||
@@ -475,6 +481,7 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
|
|||||||
ZDocumentAuditLogEventDocumentMovedToTeamSchema,
|
ZDocumentAuditLogEventDocumentMovedToTeamSchema,
|
||||||
ZDocumentAuditLogEventDocumentFieldInsertedSchema,
|
ZDocumentAuditLogEventDocumentFieldInsertedSchema,
|
||||||
ZDocumentAuditLogEventDocumentFieldUninsertedSchema,
|
ZDocumentAuditLogEventDocumentFieldUninsertedSchema,
|
||||||
|
ZDocumentAuditLogEventDocumentVisibilitySchema,
|
||||||
ZDocumentAuditLogEventDocumentGlobalAuthAccessUpdatedSchema,
|
ZDocumentAuditLogEventDocumentGlobalAuthAccessUpdatedSchema,
|
||||||
ZDocumentAuditLogEventDocumentGlobalAuthActionUpdatedSchema,
|
ZDocumentAuditLogEventDocumentGlobalAuthActionUpdatedSchema,
|
||||||
ZDocumentAuditLogEventDocumentMetaUpdatedSchema,
|
ZDocumentAuditLogEventDocumentMetaUpdatedSchema,
|
||||||
|
|||||||
7
packages/lib/types/document-visibility.ts
Normal file
7
packages/lib/types/document-visibility.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { DocumentVisibility as DocumentVisibilityEnum } from '@documenso/prisma/client';
|
||||||
|
|
||||||
|
export const ZDocumentVisibilitySchema = z.nativeEnum(DocumentVisibilityEnum);
|
||||||
|
export const DocumentVisibility = ZDocumentVisibilitySchema.enum;
|
||||||
|
export type TDocumentVisibility = z.infer<typeof ZDocumentVisibilitySchema>;
|
||||||
@@ -313,6 +313,10 @@ export const formatDocumentAuditLogAction = (auditLog: TDocumentAuditLog, userId
|
|||||||
anonymous: 'Field unsigned',
|
anonymous: 'Field unsigned',
|
||||||
identified: 'unsigned a field',
|
identified: 'unsigned a field',
|
||||||
}))
|
}))
|
||||||
|
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_VISIBILITY_UPDATED }, () => ({
|
||||||
|
anonymous: 'Document visibility updated',
|
||||||
|
identified: 'updated the document visibility',
|
||||||
|
}))
|
||||||
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED }, () => ({
|
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_GLOBAL_AUTH_ACCESS_UPDATED }, () => ({
|
||||||
anonymous: 'Document access auth updated',
|
anonymous: 'Document access auth updated',
|
||||||
identified: 'updated the document access auth requirements',
|
identified: 'updated the document access auth requirements',
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Document" ADD COLUMN "visibility" TEXT;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- The `visibility` column on the `Document` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "DocumentVisibility" AS ENUM ('EVERYONE', 'MANAGER_AND_ABOVE', 'ADMIN');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Document" DROP COLUMN "visibility",
|
||||||
|
ADD COLUMN "visibility" "DocumentVisibility" NOT NULL DEFAULT 'EVERYONE';
|
||||||
@@ -282,6 +282,12 @@ enum DocumentSource {
|
|||||||
TEMPLATE_DIRECT_LINK
|
TEMPLATE_DIRECT_LINK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DocumentVisibility {
|
||||||
|
EVERYONE
|
||||||
|
MANAGER_AND_ABOVE
|
||||||
|
ADMIN
|
||||||
|
}
|
||||||
|
|
||||||
model Document {
|
model Document {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
externalId String?
|
externalId String?
|
||||||
@@ -289,6 +295,7 @@ model Document {
|
|||||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
authOptions Json?
|
authOptions Json?
|
||||||
formValues Json?
|
formValues Json?
|
||||||
|
visibility DocumentVisibility @default(EVERYONE)
|
||||||
title String
|
title String
|
||||||
status DocumentStatus @default(DRAFT)
|
status DocumentStatus @default(DRAFT)
|
||||||
Recipient Recipient[]
|
Recipient Recipient[]
|
||||||
|
|||||||
@@ -102,6 +102,44 @@ export const unseedTeam = async (teamUrl: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SeedTeamMemberOptions = {
|
||||||
|
teamId: number;
|
||||||
|
role?: TeamMemberRole;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const seedTeamMember = async ({
|
||||||
|
teamId,
|
||||||
|
role = TeamMemberRole.ADMIN,
|
||||||
|
}: SeedTeamMemberOptions) => {
|
||||||
|
const user = await seedUser();
|
||||||
|
|
||||||
|
await prisma.teamMember.create({
|
||||||
|
data: {
|
||||||
|
teamId,
|
||||||
|
role,
|
||||||
|
userId: user.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UnseedTeamMemberOptions = {
|
||||||
|
teamId: number;
|
||||||
|
userId: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const unseedTeamMember = async ({ teamId, userId }: UnseedTeamMemberOptions) => {
|
||||||
|
await prisma.teamMember.delete({
|
||||||
|
where: {
|
||||||
|
userId_teamId: {
|
||||||
|
userId,
|
||||||
|
teamId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const seedTeamTransfer = async (options: { newOwnerUserId: number; teamId: number }) => {
|
export const seedTeamTransfer = async (options: { newOwnerUserId: number; teamId: number }) => {
|
||||||
return await prisma.teamTransferVerification.create({
|
return await prisma.teamTransferVerification.create({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export const ZSetSettingsForDocumentMutationSchema = z.object({
|
|||||||
data: z.object({
|
data: z.object({
|
||||||
title: z.string().min(1).optional(),
|
title: z.string().min(1).optional(),
|
||||||
externalId: z.string().nullish(),
|
externalId: z.string().nullish(),
|
||||||
|
visibility: z.string().optional(),
|
||||||
globalAccessAuth: ZDocumentAccessAuthTypesSchema.nullable().optional(),
|
globalAccessAuth: ZDocumentAccessAuthTypesSchema.nullable().optional(),
|
||||||
globalActionAuth: ZDocumentActionAuthTypesSchema.nullable().optional(),
|
globalActionAuth: ZDocumentActionAuthTypesSchema.nullable().optional(),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import React, { forwardRef } from 'react';
|
||||||
|
|
||||||
|
import type { SelectProps } from '@radix-ui/react-select';
|
||||||
|
import { InfoIcon } from 'lucide-react';
|
||||||
|
|
||||||
|
import { DOCUMENT_VISIBILITY } from '@documenso/lib/constants/document-visibility';
|
||||||
|
import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from '@documenso/ui/primitives/select';
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
|
||||||
|
|
||||||
|
export type DocumentVisibilitySelectType = SelectProps & {
|
||||||
|
currentMemberRole?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DocumentVisibilitySelect = forwardRef<HTMLButtonElement, DocumentVisibilitySelectType>(
|
||||||
|
({ currentMemberRole, ...props }, ref) => {
|
||||||
|
const canUpdateVisibility = currentMemberRole === 'ADMIN' || currentMemberRole === 'MANAGER';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select {...props} disabled={!canUpdateVisibility}>
|
||||||
|
<SelectTrigger ref={ref} className="bg-background text-muted-foreground">
|
||||||
|
<SelectValue data-testid="documentVisibilitySelectValue" placeholder="Everyone" />
|
||||||
|
</SelectTrigger>
|
||||||
|
|
||||||
|
<SelectContent position="popper">
|
||||||
|
<SelectItem value={DocumentVisibility.EVERYONE}>
|
||||||
|
{DOCUMENT_VISIBILITY.EVERYONE.value}
|
||||||
|
</SelectItem>
|
||||||
|
|
||||||
|
{(currentMemberRole === 'ADMIN' || currentMemberRole === 'MANAGER') && (
|
||||||
|
<SelectItem value={DocumentVisibility.MANAGER_AND_ABOVE}>
|
||||||
|
{DOCUMENT_VISIBILITY.MANAGER_AND_ABOVE.value}
|
||||||
|
</SelectItem>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{currentMemberRole === 'ADMIN' && (
|
||||||
|
<SelectItem value={DocumentVisibility.ADMIN}>
|
||||||
|
{DOCUMENT_VISIBILITY.ADMIN.value}
|
||||||
|
</SelectItem>
|
||||||
|
)}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
DocumentVisibilitySelect.displayName = 'DocumentVisibilitySelect';
|
||||||
|
|
||||||
|
export const DocumentVisibilityTooltip = () => {
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<InfoIcon className="mx-2 h-4 w-4" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
|
||||||
|
<TooltipContent className="text-foreground max-w-md space-y-2 p-4">
|
||||||
|
<h2>
|
||||||
|
<strong>Document visibility</strong>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p>The visibility of the document to the recipient.</p>
|
||||||
|
|
||||||
|
<ul className="ml-3.5 list-outside list-disc space-y-0.5 py-2">
|
||||||
|
<li>
|
||||||
|
<strong>Everyone</strong> - Everyone can access and view the document
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Managers and above</strong> - Only managers and above can access and view the
|
||||||
|
document
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Admins only</strong> - Only admins can access and view the document
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,6 +10,7 @@ import { useForm } from 'react-hook-form';
|
|||||||
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
import { DATE_FORMATS, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||||
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones';
|
||||||
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth';
|
||||||
|
import type { TeamMemberRole } from '@documenso/prisma/client';
|
||||||
import { DocumentStatus, type Field, type Recipient, SendStatus } from '@documenso/prisma/client';
|
import { DocumentStatus, type Field, type Recipient, SendStatus } from '@documenso/prisma/client';
|
||||||
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
|
import type { DocumentWithData } from '@documenso/prisma/types/document-with-data';
|
||||||
import {
|
import {
|
||||||
@@ -20,6 +21,10 @@ import {
|
|||||||
DocumentGlobalAuthActionSelect,
|
DocumentGlobalAuthActionSelect,
|
||||||
DocumentGlobalAuthActionTooltip,
|
DocumentGlobalAuthActionTooltip,
|
||||||
} from '@documenso/ui/components/document/document-global-auth-action-select';
|
} from '@documenso/ui/components/document/document-global-auth-action-select';
|
||||||
|
import {
|
||||||
|
DocumentVisibilitySelect,
|
||||||
|
DocumentVisibilityTooltip,
|
||||||
|
} from '@documenso/ui/components/document/document-visibility-select';
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
@@ -59,6 +64,7 @@ export type AddSettingsFormProps = {
|
|||||||
isDocumentEnterprise: boolean;
|
isDocumentEnterprise: boolean;
|
||||||
isDocumentPdfLoaded: boolean;
|
isDocumentPdfLoaded: boolean;
|
||||||
document: DocumentWithData;
|
document: DocumentWithData;
|
||||||
|
currentTeamMemberRole?: TeamMemberRole;
|
||||||
onSubmit: (_data: TAddSettingsFormSchema) => void;
|
onSubmit: (_data: TAddSettingsFormSchema) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,6 +75,7 @@ export const AddSettingsFormPartial = ({
|
|||||||
isDocumentEnterprise,
|
isDocumentEnterprise,
|
||||||
isDocumentPdfLoaded,
|
isDocumentPdfLoaded,
|
||||||
document,
|
document,
|
||||||
|
currentTeamMemberRole,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
}: AddSettingsFormProps) => {
|
}: AddSettingsFormProps) => {
|
||||||
const { documentAuthOption } = extractDocumentAuthMethods({
|
const { documentAuthOption } = extractDocumentAuthMethods({
|
||||||
@@ -80,6 +87,7 @@ export const AddSettingsFormPartial = ({
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
title: document.title,
|
title: document.title,
|
||||||
externalId: document.externalId || '',
|
externalId: document.externalId || '',
|
||||||
|
visibility: document.visibility || '',
|
||||||
globalAccessAuth: documentAuthOption?.globalAccessAuth || undefined,
|
globalAccessAuth: documentAuthOption?.globalAccessAuth || undefined,
|
||||||
globalActionAuth: documentAuthOption?.globalActionAuth || undefined,
|
globalActionAuth: documentAuthOption?.globalActionAuth || undefined,
|
||||||
meta: {
|
meta: {
|
||||||
@@ -174,6 +182,29 @@ export const AddSettingsFormPartial = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{currentTeamMemberRole && (
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="visibility"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel className="flex flex-row items-center">
|
||||||
|
Document visibility
|
||||||
|
<DocumentVisibilityTooltip />
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<DocumentVisibilitySelect
|
||||||
|
currentMemberRole={currentTeamMemberRole}
|
||||||
|
{...field}
|
||||||
|
onValueChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{isDocumentEnterprise && (
|
{isDocumentEnterprise && (
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export const ZMapNegativeOneToUndefinedSchema = z
|
|||||||
export const ZAddSettingsFormSchema = z.object({
|
export const ZAddSettingsFormSchema = z.object({
|
||||||
title: z.string().trim().min(1, { message: "Title can't be empty" }),
|
title: z.string().trim().min(1, { message: "Title can't be empty" }),
|
||||||
externalId: z.string().optional(),
|
externalId: z.string().optional(),
|
||||||
|
visibility: z.string().optional(),
|
||||||
globalAccessAuth: ZMapNegativeOneToUndefinedSchema.pipe(
|
globalAccessAuth: ZMapNegativeOneToUndefinedSchema.pipe(
|
||||||
ZDocumentAccessAuthTypesSchema.optional(),
|
ZDocumentAccessAuthTypesSchema.optional(),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user