From 283c6d274b1f7061249e2470d5ac28bf02de2acc Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Mon, 17 Aug 2026 15:23:19 +1000 Subject: [PATCH 01/64] fix: use documenso fork of skia-canvas for rendering (#3214) Use our fork of `skia-canvas` for rendering which handles encoding characters correctly with the caveat font and other similar fonts that can group glyphs like ligatures. This resolves issues with pdf text extraction where characters were unable to be extracted due to lacking any data within the cmaps. --- .npmrc | 2 +- apps/remix/vite.config.ts | 2 +- package-lock.json | 29 ++++++++++--------- package.json | 1 + packages/lib/package.json | 2 +- packages/lib/server-only/ai/pdf-to-images.ts | 2 +- .../lib/server-only/konva/skia-backend.ts | 5 ++-- packages/lib/server-only/pdf/helpers.ts | 2 +- .../server-only/pdf/insert-field-in-pdf-v2.ts | 2 +- .../lib/server-only/pdf/render-audit-logs.ts | 12 ++++---- .../lib/server-only/pdf/render-certificate.ts | 12 ++++---- .../field-renderer/render-signature-field.ts | 2 +- 12 files changed, 40 insertions(+), 33 deletions(-) diff --git a/.npmrc b/.npmrc index 75baad7f0..cbc6b6537 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,3 @@ legacy-peer-deps = true prefer-dedupe = true -# min-release-age = 7 +min-release-age = 7 diff --git a/apps/remix/vite.config.ts b/apps/remix/vite.config.ts index 50d21e07d..b6cc0cb1b 100644 --- a/apps/remix/vite.config.ts +++ b/apps/remix/vite.config.ts @@ -121,7 +121,7 @@ export default defineConfig({ 'nodemailer', /playwright/, '@playwright/browser-chromium', - 'skia-canvas', + '@documenso/skia-canvas', ], }, }, diff --git a/package-lock.json b/package-lock.json index a10151db2..4c13b8e33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@commitlint/cli": "^20.1.0", "@commitlint/config-conventional": "^20.0.0", "@datadog/pprof": "^5.13.5", + "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/cli": "^5.6.0", "@prisma/client": "^6.19.0", "@trpc/client": "11.8.1", @@ -3515,6 +3516,19 @@ "resolved": "packages/signing", "link": true }, + "node_modules/@documenso/skia-canvas": { + "version": "3.0.8-documenso.3", + "resolved": "https://registry.npmjs.org/@documenso/skia-canvas/-/skia-canvas-3.0.8-documenso.3.tgz", + "integrity": "sha512-IeEr7RxJigCzidsRIQu6tcMX9+bt0tG3Y5kMArCPF4/jEgunPVx3qd7Wyh34mtSNufpzmVwazxR+U2BIz3iYvQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.1.1", + "follow-redirects": "^1.15.11", + "https-proxy-agent": "^7.0.6", + "string-split-by": "^1.0.0" + } + }, "node_modules/@documenso/tailwind-config": { "resolved": "packages/tailwind-config", "link": true @@ -28728,19 +28742,6 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, - "node_modules/skia-canvas": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/skia-canvas/-/skia-canvas-3.0.8.tgz", - "integrity": "sha512-FSYKxp8Ng2vOeeOBiyPhnn6ui6FirPJXMyjk4PKl8N/OWzVrkMawUgY9zubIWHMdYtyWFn0gfX3QlRwg6HBmdg==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.1.1", - "follow-redirects": "^1.15.11", - "https-proxy-agent": "^7.0.6", - "string-split-by": "^1.0.0" - } - }, "node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -33231,6 +33232,7 @@ "@documenso/email": "*", "@documenso/prisma": "*", "@documenso/signing": "*", + "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/core": "^5.6.0", "@lingui/macro": "^5.6.0", "@lingui/react": "^5.6.0", @@ -33269,7 +33271,6 @@ "react": "^18", "remeda": "^2.32.0", "sharp": "0.34.5", - "skia-canvas": "^3.0.8", "stripe": "^12.18.0", "ts-pattern": "^5.9.0", "zod": "^3.25.76" diff --git a/package.json b/package.json index 60e97f1c8..d4382924d 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "@commitlint/cli": "^20.1.0", "@commitlint/config-conventional": "^20.0.0", "@datadog/pprof": "^5.13.5", + "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/cli": "^5.6.0", "@prisma/client": "^6.19.0", "@trpc/client": "11.8.1", diff --git a/packages/lib/package.json b/packages/lib/package.json index 41b1f1815..27092f178 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -29,6 +29,7 @@ "@documenso/email": "*", "@documenso/prisma": "*", "@documenso/signing": "*", + "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/core": "^5.6.0", "@lingui/macro": "^5.6.0", "@lingui/react": "^5.6.0", @@ -67,7 +68,6 @@ "react": "^18", "remeda": "^2.32.0", "sharp": "0.34.5", - "skia-canvas": "^3.0.8", "stripe": "^12.18.0", "ts-pattern": "^5.9.0", "zod": "^3.25.76" diff --git a/packages/lib/server-only/ai/pdf-to-images.ts b/packages/lib/server-only/ai/pdf-to-images.ts index e14128278..fb2ee13e8 100644 --- a/packages/lib/server-only/ai/pdf-to-images.ts +++ b/packages/lib/server-only/ai/pdf-to-images.ts @@ -1,6 +1,6 @@ +import { Canvas, Image, Path2D } from '@documenso/skia-canvas'; import pMap from 'p-map'; import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs'; -import { Canvas, Image, Path2D } from 'skia-canvas'; // @ts-expect-error napi-rs/canvas satisfies the requirements globalThis.Path2D = Path2D; diff --git a/packages/lib/server-only/konva/skia-backend.ts b/packages/lib/server-only/konva/skia-backend.ts index bdcd4ec64..1e41c51ab 100644 --- a/packages/lib/server-only/konva/skia-backend.ts +++ b/packages/lib/server-only/konva/skia-backend.ts @@ -2,8 +2,9 @@ * !: This is a workaround to fix the memory leak in the skia-canvas library. * !: Internals are ported from the original `konva/skia-backend.js` file. */ + +import { Canvas, DOMMatrix, Image, Path2D } from '@documenso/skia-canvas'; import { Konva } from 'konva/lib/_CoreInternals'; -import { Canvas, DOMMatrix, Image, Path2D } from 'skia-canvas'; // @ts-expect-error skia-canvas satisfies the requirements global.DOMMatrix = DOMMatrix; @@ -37,6 +38,6 @@ Konva.Util.createImageElement = () => { return node as unknown as HTMLImageElement; }; -Konva._renderBackend = 'skia-canvas'; +Konva._renderBackend = '@documenso/skia-canvas'; export default Konva; diff --git a/packages/lib/server-only/pdf/helpers.ts b/packages/lib/server-only/pdf/helpers.ts index 2d6a1bc7e..afe53e170 100644 --- a/packages/lib/server-only/pdf/helpers.ts +++ b/packages/lib/server-only/pdf/helpers.ts @@ -1,8 +1,8 @@ import path from 'node:path'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; +import { FontLibrary } from '@documenso/skia-canvas'; import type { Recipient } from '@prisma/client'; import { FieldType } from '@prisma/client'; -import { FontLibrary } from 'skia-canvas'; import { match } from 'ts-pattern'; /** diff --git a/packages/lib/server-only/pdf/insert-field-in-pdf-v2.ts b/packages/lib/server-only/pdf/insert-field-in-pdf-v2.ts index ad2adff2c..ee337c1e9 100644 --- a/packages/lib/server-only/pdf/insert-field-in-pdf-v2.ts +++ b/packages/lib/server-only/pdf/insert-field-in-pdf-v2.ts @@ -2,8 +2,8 @@ import '../konva/skia-backend'; import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature'; +import type { Canvas } from '@documenso/skia-canvas'; import Konva from 'konva'; -import type { Canvas } from 'skia-canvas'; import { renderField } from '../../universal/field-renderer/render-field'; import { ensureFontLibrary } from './helpers'; diff --git a/packages/lib/server-only/pdf/render-audit-logs.ts b/packages/lib/server-only/pdf/render-audit-logs.ts index faf982f55..427ed8be1 100644 --- a/packages/lib/server-only/pdf/render-audit-logs.ts +++ b/packages/lib/server-only/pdf/render-audit-logs.ts @@ -1,14 +1,16 @@ +// sort-imports-ignore +import '../konva/skia-backend'; + +import fs from 'node:fs'; +import path from 'node:path'; +import type { Canvas } from '@documenso/skia-canvas'; +import { Image as SkiaImage } from '@documenso/skia-canvas'; import type { I18n } from '@lingui/core'; import { msg } from '@lingui/core/macro'; import type { DocumentMeta, Envelope, RecipientRole } from '@prisma/client'; import Konva from 'konva'; -import 'konva/skia-backend'; -import fs from 'node:fs'; -import path from 'node:path'; import type { DateTimeFormatOptions } from 'luxon'; import { DateTime } from 'luxon'; -import type { Canvas } from 'skia-canvas'; -import { Image as SkiaImage } from 'skia-canvas'; import { match, P } from 'ts-pattern'; import { UAParser } from 'ua-parser-js'; diff --git a/packages/lib/server-only/pdf/render-certificate.ts b/packages/lib/server-only/pdf/render-certificate.ts index a30d265ee..9fa2a73c9 100644 --- a/packages/lib/server-only/pdf/render-certificate.ts +++ b/packages/lib/server-only/pdf/render-certificate.ts @@ -1,14 +1,16 @@ +// sort-imports-ignore +import '../konva/skia-backend'; + +import fs from 'node:fs'; +import path from 'node:path'; +import type { Canvas } from '@documenso/skia-canvas'; +import { Image as SkiaImage } from '@documenso/skia-canvas'; import type { I18n } from '@lingui/core'; import { msg } from '@lingui/core/macro'; import type { Field, RecipientRole, Signature } from '@prisma/client'; import { SigningStatus } from '@prisma/client'; import Konva from 'konva'; -import 'konva/skia-backend'; -import fs from 'node:fs'; -import path from 'node:path'; import { DateTime } from 'luxon'; -import type { Canvas } from 'skia-canvas'; -import { Image as SkiaImage } from 'skia-canvas'; import { UAParser } from 'ua-parser-js'; import { renderSVG } from 'uqr'; diff --git a/packages/lib/universal/field-renderer/render-signature-field.ts b/packages/lib/universal/field-renderer/render-signature-field.ts index a43d46115..eb3d94c57 100644 --- a/packages/lib/universal/field-renderer/render-signature-field.ts +++ b/packages/lib/universal/field-renderer/render-signature-field.ts @@ -14,7 +14,7 @@ let SkiaImage: any; void (async () => { if (typeof window === 'undefined') { - const mod = await import('skia-canvas'); + const mod = await import('@documenso/skia-canvas'); SkiaImage = mod.Image; } })(); From 779de01fe8fb8c242da867b6c1fa38c70e448c3a Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Mon, 17 Aug 2026 16:58:11 +1000 Subject: [PATCH 02/64] feat: migrate to react 19 (#3107) --- apps/docs/package.json | 1 - apps/openpage-api/package.json | 2 +- .../components/general/app-command-menu.tsx | 2 +- .../document-signing-radio-field.tsx | 10 +- .../general/pdf-viewer/pdf-viewer.tsx | 2 +- apps/remix/app/entry.client.tsx | 21 + apps/remix/package.json | 8 +- package-lock.json | 3632 +++++++---------- package.json | 42 +- packages/ee/package.json | 2 +- packages/email/components.ts | 36 +- packages/email/package.json | 22 +- .../lib/client-only/hooks/use-autosave.ts | 2 +- .../providers/envelope-editor-provider.tsx | 78 +- packages/lib/package.json | 2 +- packages/trpc/package.json | 6 +- packages/ui/components/signing-card.tsx | 2 +- packages/ui/package.json | 41 +- packages/ui/primitives/command.tsx | 4 +- .../document-flow/field-content.tsx | 9 +- .../ui/primitives/recipient-role-icons.tsx | 1 + .../signature-pad/signature-pad-draw.tsx | 2 +- 22 files changed, 1532 insertions(+), 2395 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 9f345d14c..be8dfc789 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -10,7 +10,6 @@ "postinstall": "fumadocs-mdx" }, "dependencies": { - "@radix-ui/react-tabs": "^1.1.13", "fumadocs-core": "16.5.0", "fumadocs-mdx": "14.2.6", "fumadocs-ui": "16.5.0", diff --git a/apps/openpage-api/package.json b/apps/openpage-api/package.json index bcc93e039..4efc1dff8 100644 --- a/apps/openpage-api/package.json +++ b/apps/openpage-api/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@types/node": "^20", - "@types/react": "18.3.27", + "@types/react": "^19.2.17", "typescript": "5.6.2" } } diff --git a/apps/remix/app/components/general/app-command-menu.tsx b/apps/remix/app/components/general/app-command-menu.tsx index 7f245872f..32b6a7865 100644 --- a/apps/remix/app/components/general/app-command-menu.tsx +++ b/apps/remix/app/components/general/app-command-menu.tsx @@ -19,7 +19,7 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { keepPreviousData } from '@tanstack/react-query'; -import { commandScore } from 'cmdk/dist/command-score'; +import { defaultFilter as commandScore } from 'cmdk'; import { ArrowLeftIcon, CheckIcon, diff --git a/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx index 71a0cfa38..e9d6af196 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx @@ -146,14 +146,17 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }: {isLoading && } {!field.inserted && ( - handleSelectItem(value)} className="z-10 my-0.5 gap-y-1"> + handleSelectItem(value)} + className="z-10 my-0.5 gap-y-1" + > {values?.map((item, index) => (
{!item.value.includes('empty-value-') && item.value && ( @@ -167,14 +170,13 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }: )} {field.inserted && ( - + {values?.map((item, index) => (
{!item.value.includes('empty-value-') && item.value && ( diff --git a/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx b/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx index 56c5308d6..c795485f2 100644 --- a/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx +++ b/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx @@ -215,7 +215,7 @@ export default function PDFViewer({ type VirtualizedPageListProps = { scrollParentRef: ScrollTarget; - constraintRef: React.RefObject; + constraintRef: React.RefObject; pages: PageMeta[]; numPages: number; pdf: pdfjsLib.PDFDocumentProxy; diff --git a/apps/remix/app/entry.client.tsx b/apps/remix/app/entry.client.tsx index 0ffb3602e..f76430676 100644 --- a/apps/remix/app/entry.client.tsx +++ b/apps/remix/app/entry.client.tsx @@ -31,6 +31,26 @@ function initPosthog() { } } +/** + * Surfaces hydration recoveries (React 19 discards the server HTML and + * re-renders on the client instead of dying) so we can track how often + * extensions/early clicks interfere with hydration in the wild. + */ +function onRecoverableError(error: unknown, errorInfo: { componentStack?: string }) { + console.error('[hydration] recovered from error', error, errorInfo.componentStack); + + if (extractPostHogConfig()) { + void import('posthog-js').then(({ default: posthog }) => { + if (posthog.__loaded) { + posthog.capture('$hydration_recoverable_error', { + message: error instanceof Error ? error.message : String(error), + componentStack: errorInfo.componentStack, + }); + } + }); + } +} + async function main() { const locale = detect(fromHtmlTag('lang')) || 'en'; @@ -44,6 +64,7 @@ async function main() { , + { onRecoverableError }, ); }); diff --git a/apps/remix/package.json b/apps/remix/package.json index daa376df3..4674c249d 100644 --- a/apps/remix/package.json +++ b/apps/remix/package.json @@ -57,9 +57,9 @@ "papaparse": "^5.5.3", "posthog-js": "^1.297.2", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", "react-call": "^1.8.1", - "react-dom": "^18", + "react-dom": "^19.2.7", "react-dropzone": "^14.3.8", "react-hook-form": "^7.66.1", "react-hotkeys-hook": "^4.6.2", @@ -93,8 +93,8 @@ "@types/luxon": "^3.7.1", "@types/node": "^20", "@types/papaparse": "^5.5.0", - "@types/react": "18.3.27", - "@types/react-dom": "^18", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "@types/ua-parser-js": "^0.7.39", "cross-env": "^10.1.0", "esbuild": "^0.27.0", diff --git a/package-lock.json b/package-lock.json index 4c13b8e33..c17553bfc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,13 +20,41 @@ "@lingui/core": "^5.6.0", "@marsidev/react-turnstile": "^1.5.0", "@prisma/extension-read-replicas": "^0.4.1", + "@radix-ui/react-accordion": "^1.2.16", + "@radix-ui/react-alert-dialog": "^1.1.19", + "@radix-ui/react-aspect-ratio": "^1.1.11", + "@radix-ui/react-avatar": "^1.2.2", + "@radix-ui/react-checkbox": "^1.3.7", + "@radix-ui/react-collapsible": "^1.1.16", + "@radix-ui/react-context-menu": "^2.3.3", + "@radix-ui/react-dialog": "^1.1.19", + "@radix-ui/react-dropdown-menu": "^2.1.20", + "@radix-ui/react-hover-card": "^1.1.19", + "@radix-ui/react-label": "^2.1.11", + "@radix-ui/react-menubar": "^1.1.20", + "@radix-ui/react-navigation-menu": "^1.2.18", + "@radix-ui/react-popover": "^1.1.19", + "@radix-ui/react-progress": "^1.1.12", + "@radix-ui/react-radio-group": "^1.4.3", + "@radix-ui/react-scroll-area": "^1.2.14", + "@radix-ui/react-select": "^2.3.3", + "@radix-ui/react-separator": "^1.1.11", + "@radix-ui/react-slider": "^1.4.3", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-switch": "^1.3.3", + "@radix-ui/react-tabs": "^1.1.17", + "@radix-ui/react-toast": "^1.2.19", + "@radix-ui/react-toggle": "^1.1.14", + "@radix-ui/react-toggle-group": "^1.1.15", + "@radix-ui/react-tooltip": "^1.2.12", "ai": "^5.0.104", "cron-parser": "^5.5.0", "fflate": "^0.8.3", "luxon": "^3.7.2", "patch-package": "^8.0.1", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", + "react-dom": "^19.2.7", "typescript": "5.6.2", "zod": "^3.25.76" }, @@ -38,12 +66,14 @@ "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/cli": "^5.6.0", "@prisma/client": "^6.19.0", - "@trpc/client": "11.8.1", - "@trpc/react-query": "11.8.1", - "@trpc/server": "11.8.1", + "@trpc/client": "11.17.0", + "@trpc/react-query": "11.17.0", + "@trpc/server": "11.17.0", "@ts-rest/core": "^3.52.1", "@ts-rest/open-api": "^3.52.1", "@ts-rest/serverless": "^3.52.1", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "dotenv": "^17.2.3", "dotenv-cli": "^11.0.0", "esbuild": "^0.27.0", @@ -80,7 +110,6 @@ "version": "0.0.0", "hasInstallScript": true, "dependencies": { - "@radix-ui/react-tabs": "^1.1.13", "fumadocs-core": "16.5.0", "fumadocs-mdx": "14.2.6", "fumadocs-ui": "16.5.0", @@ -114,26 +143,6 @@ "undici-types": ">=7.24.0 <7.24.7" } }, - "apps/docs/node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "apps/docs/node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, "apps/docs/node_modules/chokidar": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", @@ -254,27 +263,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "apps/docs/node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "apps/docs/node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.7" - } - }, "apps/docs/node_modules/readdirp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", @@ -288,12 +276,6 @@ "url": "https://paulmillr.com/funding/" } }, - "apps/docs/node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, "apps/docs/node_modules/tailwind-merge": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", @@ -362,7 +344,7 @@ }, "devDependencies": { "@types/node": "^20", - "@types/react": "18.3.27", + "@types/react": "^19.2.17", "typescript": "5.6.2" } }, @@ -413,9 +395,9 @@ "papaparse": "^5.5.3", "posthog-js": "^1.297.2", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", "react-call": "^1.8.1", - "react-dom": "^18", + "react-dom": "^19.2.7", "react-dropzone": "^14.3.8", "react-hook-form": "^7.66.1", "react-hotkeys-hook": "^4.6.2", @@ -449,8 +431,8 @@ "@types/luxon": "^3.7.1", "@types/node": "^20", "@types/papaparse": "^5.5.0", - "@types/react": "18.3.27", - "@types/react-dom": "^18", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "@types/ua-parser-js": "^0.7.39", "cross-env": "^10.1.0", "esbuild": "^0.27.0", @@ -2858,6 +2840,7 @@ "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.7", @@ -4022,31 +4005,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", - "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.10" + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", - "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.3", - "@floating-ui/utils": "^0.2.10" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", - "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.4" + "@floating-ui/dom": "^1.7.6" }, "peerDependencies": { "react": ">=16.8.0", @@ -4054,9 +4037,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", - "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, "node_modules/@formatjs/fast-memoize": { @@ -4240,22 +4223,20 @@ } }, "node_modules/@hello-pangea/dnd": { - "version": "16.6.0", - "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-16.6.0.tgz", - "integrity": "sha512-vfZ4GydqbtUPXSLfAvKvXQ6xwRzIjUSjVU0Sx+70VOhc2xx6CdmJXJ8YhH70RpbTUGjxctslQTHul9sIOxCfFQ==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-18.0.1.tgz", + "integrity": "sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==", "license": "Apache-2.0", "dependencies": { - "@babel/runtime": "^7.24.1", + "@babel/runtime": "^7.26.7", "css-box-model": "^1.2.1", - "memoize-one": "^6.0.0", "raf-schd": "^4.0.3", - "react-redux": "^8.1.3", - "redux": "^4.2.1", - "use-memo-one": "^1.1.3" + "react-redux": "^9.2.0", + "redux": "^5.0.1" }, "peerDependencies": { - "react": "^16.8.5 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" } }, "node_modules/@hexagon/base64": { @@ -10811,32 +10792,32 @@ "license": "BSD-3-Clause" }, "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.2.tgz", + "integrity": "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==", "license": "MIT" }, "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.5.tgz", + "integrity": "sha512-d86WIWFYNtGA0H/d8exstrTRTp7eWJYlYJbtNofxr/3ljupZYn6EFDG/Qgu/0Kc8v7yMUxySagqJsL1+PdYjWg==", "license": "MIT" }, "node_modules/@radix-ui/react-accordion": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", - "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.16.tgz", + "integrity": "sha512-BpZJNmetujnGgUI6OX0jEhEmlA46WPqgub8Rv09Kyquwd0cc1ndMKpiPYCjmBU6KSSRPAMtgLpEoZSG/tdNIWQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collapsible": "1.1.16", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -10854,17 +10835,16 @@ } }, "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", - "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.19.tgz", + "integrity": "sha512-FA7n1f6D/DwGE0+AWxiY5LacNbbExQuEgMubeG06idEaH+mSLuf9dp/qBNqOnvbTQ+4gZ2ue1RATF1Ub91Mg5g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dialog": "1.1.15", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dialog": "1.1.19", + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -10881,31 +10861,13 @@ } } }, - "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz", + "integrity": "sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -10923,35 +10885,12 @@ } }, "node_modules/@radix-ui/react-aspect-ratio": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.8.tgz", - "integrity": "sha512-5nZrJTF7gH+e0nZS7/QxFz6tJV4VimhQb1avEgtsJxvvIp5JilL+c58HICsKzPxghdwaDt48hEfPM1au4zGy+w==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.11.tgz", + "integrity": "sha512-IUAhIVpBUvP5NNICjlaB1OFmtRLGqQqTF3ZOSGPoq3XeLXRFtHiWTRxSVEULgOd9GQR2c7tsYqDnhUennapZnw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-aspect-ratio/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -10969,54 +10908,16 @@ } }, "node_modules/@radix-ui/react-avatar": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", - "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.2.2.tgz", + "integrity": "sha512-sST0qh8GzOB7besQ3tMLWLyngnRuSk0gc/Hm+667KYKQFCt6Y6ZXv25WlqM7dIDK54ULCh5+CHmk4LIolzfz+A==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", - "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-avatar/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11034,19 +10935,19 @@ } }, "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", - "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.7.tgz", + "integrity": "sha512-JroKHfQBfh+fDuzpPsBC+pESkhuq8ql4hljTguz8MWnS35cISr3d/Jhl9kYrB44FlDtxCArYdDvTx+BSsJ64rQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11064,19 +10965,19 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.16.tgz", + "integrity": "sha512-opfXRe6nnzyGmCDPx+l1Aqo/RbqWtQal2FnsBqF9hhePp6j0LsRoBaRxcMOlTv+uYTJVtWYZKg9t9wTe+BA/ZA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11094,15 +10995,15 @@ } }, "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.12.tgz", + "integrity": "sha512-nb67INpE0IahJKN7EYPp9m9YGwYeKlnzxT3MwXVkgCskaSJia97kG4T0ywpjNUSSnoJk/uvk12V8vbrEHEj+/Q==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -11119,28 +11020,10 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", + "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -11153,9 +11036,9 @@ } }, "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.0.tgz", + "integrity": "sha512-fOE+JtN9rygNZkCnHRBEP0TAvLldlhyOxMsbwFvTP4nAs+nBmfnna+o/Zski2wkmY1YMrFC0aSzsHoLY47iLrg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -11168,17 +11051,16 @@ } }, "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", - "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.3.3.tgz", + "integrity": "sha512-PS+gKE0z2prJ74Y0sM+brAGK4mYOHIR7TlcV5EJgUQ6E0xMvyswkK2X4yRqyganrzsRL+WCSKAPu0NQITICRWg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-menu": "2.1.20", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -11196,25 +11078,25 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.19.tgz", + "integrity": "sha512-+HhbN2+YtkRgVirjZ2afMeutQRuGOrdkWR5+EFC58SJojGmtyNQwYzgi6tHBpOxvFHefMtPeHdgtjz0BOGxFQg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -11231,28 +11113,10 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", + "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -11265,16 +11129,16 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.15.tgz", + "integrity": "sha512-b0XaRlzn2QKuo10XyNgi2DAJDf5XC9d1nD3FJcuvCjbR7+4Ad28zmZsLsqx+hvDEzMnRuZaZxZm9gYObV6RmRA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-effect-event": "0.0.3" }, "peerDependencies": { "@types/react": "*", @@ -11292,18 +11156,18 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.20.tgz", + "integrity": "sha512-slfm+rRaZRuQBvHq60lXvSVUPhid0IPtjSZzIuUlWZMUs01iYZNlGS3mJgRD3ChLQVBAYlKiL/tFyWGX+dz8Xw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.20", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -11321,9 +11185,9 @@ } }, "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", + "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -11336,14 +11200,14 @@ } }, "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.12.tgz", + "integrity": "sha512-jjk/lqTeNL0azUx5ZYzVrl4NgaDIrdzTNE4mABV9yBFI7FQqN7pIgzV1bTleUezP2QiTGA1BFTqY8MegDgWX9A==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11361,20 +11225,20 @@ } }, "node_modules/@radix-ui/react-hover-card": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", - "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.19.tgz", + "integrity": "sha512-2KTgMLQtKvicznQgbindEI2RZ3QbDIwU5gabjUPwFJsormjGDz+rUvO4NANmYwzEEpTcTONUt33vBHIfTIVSfw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -11392,12 +11256,12 @@ } }, "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", + "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11410,35 +11274,12 @@ } }, "node_modules/@radix-ui/react-label": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", - "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.11.tgz", + "integrity": "sha512-3PKvDDxOn62k0oV1n4QtNtD2vpu+zYjXR7ojLBPaO6SPvhy53yg0vAmgNeBQeJW5rV3dffoRG+HYfLBZuzw0CQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -11456,29 +11297,29 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.20.tgz", + "integrity": "sha512-VsUrXxFe9d2ScbZF0fR/oPR1+qjyeLs5p0jzG8h90puMoA9bq4SirYlXbE+USRg9Q2qTeJSFNqjw2nts8jJe4w==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -11495,40 +11336,22 @@ } } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-menubar": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", - "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.20.tgz", + "integrity": "sha512-gzFZvybgmwYsFBWDqanycIoEYnhyk8MMnuLamdFVHUZYGp4COM+sqXiwbnn0VMWqGLeeU7GV7jm+dXRa+Wufag==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.20", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -11546,25 +11369,25 @@ } }, "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", - "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.18.tgz", + "integrity": "sha512-K9HiuxZ6xCwSaHcIuUpxyhy4w5gpwzWjh9dHTSbMN3Ix4qAyVObS9RlU3zMycb0PO3v9Tpk0BXMwWvXOUbVXew==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.7" }, "peerDependencies": { "@types/react": "*", @@ -11582,26 +11405,26 @@ } }, "node_modules/@radix-ui/react-popover": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", - "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.19.tgz", + "integrity": "sha512-jkrTdQVxnIB8fpn0NyyxW9CTB5aCXZZelVz5z+Xmii6g5WxMqS3fInNslZ63puP39+Puu4jYohUK31y3dT87gQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -11618,40 +11441,22 @@ } } }, - "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.3.tgz", + "integrity": "sha512-mS7dGpyjv6b+gsDjLF7e0ia1W4Im1B1hSCy2yuXlHuvnZxHKagfDaobt/KAKt27EpZMit2pss8eJBVyVjEWM+g==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" + "@radix-ui/react-arrow": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-rect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11669,13 +11474,13 @@ } }, "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", + "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11693,13 +11498,12 @@ } }, "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.7.tgz", + "integrity": "sha512-zBZ4QM5XG3JRanDmqXYf3MD6th4AFXFmgU6KNMFzUaV6F3uw9I5/zjMUvFriSEn5ewo1nxuibvyxJdmLlDcslA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11717,12 +11521,12 @@ } }, "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz", + "integrity": "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -11739,70 +11543,14 @@ } } }, - "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", - "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.12.tgz", + "integrity": "sha512-ZPHyI0JyzoH/rP0tq2uRaIZTj/4s8+kAbqPz+e2N8+ejHvwPJ889dHhqn+vh7PNvNeq+boAoH9yzqeoShzwF2w==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", - "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -11820,21 +11568,21 @@ } }, "node_modules/@radix-ui/react-radio-group": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", - "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.4.3.tgz", + "integrity": "sha512-WwZFjWV4s3aC1QtR3k04R+oANHtX2q6fgKlc7MCEiDNlnTxCZ3H8k3mHtEgVlOejystwk1WQgarQhNOQZ2bK1g==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11852,20 +11600,22 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.15.tgz", + "integrity": "sha512-40svmmugfM3mUN7VUDGVE1tQGOhyi8enlGD0CNJEcMM36C1f71PKM21DFgNHUfem0XnA+d8H8oN3Z9ZpJjSslg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11883,20 +11633,20 @@ } }, "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", - "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.14.tgz", + "integrity": "sha512-bBODCWZK7JTbQLHs0uIP4f73wIWatakK4OS33UzkR1x897wu0PuO658a3f+6P2GEGyDzGYMuHRatMVoAk9WZTw==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -11914,32 +11664,33 @@ } }, "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", - "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.3.tgz", + "integrity": "sha512-L5RQTXz6Anxsf9CCv+pTgiAsUpyVj7rJxsGtmhFaEOJ++cVfXucv4qWfsIO0AIB4NAhi3yovWGVMKKS1Xf1Wrg==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.12", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.7", "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -11956,54 +11707,13 @@ } } }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", - "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.11.tgz", + "integrity": "sha512-jRhe86+8PF7VZ1u14eOWVOuh2BuAhALg/FT1VcMC4OHedMTRUazDnDlKTt+yxo5cRNKHMfmvZ4sSQtWDeMV4CQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -12021,22 +11731,22 @@ } }, "node_modules/@radix-ui/react-slider": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", - "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.4.3.tgz", + "integrity": "sha512-CWVVj+XaTom0SKCqw1EUgb0NuiLwS+N3OFG73mVEezKEjgNIvZiu0EevMelSSU+CbX3owbqJweG2gPU31WGC5A==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12054,12 +11764,12 @@ } }, "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", @@ -12072,18 +11782,18 @@ } }, "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", - "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.3.3.tgz", + "integrity": "sha512-1+mlB4/lxJfk5tgJ4g+R5mUCbRpPE1T9+UsEyeLYbGgMtwiMgmuTnfKz4Mw1nHALHjuwyxw4MLd4cSHn6pNSlQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12101,19 +11811,19 @@ } }, "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.17.tgz", + "integrity": "sha512-nRyXnrAVCwjeXcHbvEbLS6ndbTeKHG1RqCP4A8Gw5L4cemDzPXdD8rAmr6wet0v57R69wGvuIIsFjHSVkZiMzQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -12131,23 +11841,23 @@ } }, "node_modules/@radix-ui/react-toast": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", - "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "version": "1.2.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.19.tgz", + "integrity": "sha512-SxfVZfVOibWKWdkf0Xx1awW2d09fQu4V4PXDY1j5hi4MVf7MWdJZqTBJMa1KWtOr1S6GGtCk02nniZ0Iia+dHw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-collection": "1.1.12", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.7" }, "peerDependencies": { "@types/react": "*", @@ -12165,14 +11875,14 @@ } }, "node_modules/@radix-ui/react-toggle": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", - "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.14.tgz", + "integrity": "sha512-QI/hB65XKWACA66P64A+aHxtLUgHJeJLkaQa+awUNXT6T3swndtY5DojeHA+vldrTspMTtFBd7HfZ9QGbM1Qrw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -12190,18 +11900,18 @@ } }, "node_modules/@radix-ui/react-toggle-group": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", - "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.15.tgz", + "integrity": "sha512-gIC5Q+Xljg7lmUdzSuDoy0t97yZn1sZl00Ra37ZvKrYdWnQLU6sWLd09yG8cIB9jUAlQfHgJ2ACAG00MFwsqSQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-toggle": "1.1.10", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.15", + "@radix-ui/react-toggle": "1.1.14", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -12219,23 +11929,23 @@ } }, "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", - "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.12.tgz", + "integrity": "sha512-U3HoftgWnmla78vzQbLvKKb7bUYJxoiiqYFzp1wu/TBMyDqMZSuCl3aRICsD6EfVEwcJD2mumGDGUXLFVqQHKA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/primitive": "1.1.5", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.2.0", + "@radix-ui/react-dismissable-layer": "1.1.15", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.3", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.7", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-visually-hidden": "1.2.7" }, "peerDependencies": { "@types/react": "*", @@ -12252,28 +11962,10 @@ } } }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", + "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -12286,13 +11978,13 @@ } }, "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", + "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12305,30 +11997,12 @@ } }, "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", + "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12341,13 +12015,10 @@ } }, "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", - "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", + "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.5.0" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -12359,9 +12030,9 @@ } }, "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", + "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -12374,9 +12045,9 @@ } }, "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.2.tgz", + "integrity": "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -12389,12 +12060,12 @@ } }, "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", + "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", "license": "MIT", "dependencies": { - "@radix-ui/rect": "1.1.1" + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12407,12 +12078,12 @@ } }, "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", + "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -12425,12 +12096,12 @@ } }, "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz", + "integrity": "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -12448,293 +12119,30 @@ } }, "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.2.tgz", + "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", "license": "MIT" }, - "node_modules/@react-email/body": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@react-email/body/-/body-0.2.0.tgz", - "integrity": "sha512-9GCWmVmKUAoRfloboCd+RKm6X17xn7eGL7HnpAZUnjBXBilWCxsKnLMTC/ixSHDKS/A/057M1Tx6ZUXd89sVBw==", - "license": "MIT", - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/button": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.2.0.tgz", - "integrity": "sha512-8i+v6cMxr2emz4ihCrRiYJPp2/sdYsNNsBzXStlcA+/B9Umpm5Jj3WJKYpgTPM+aeyiqlG/MMI1AucnBm4f1oQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/code-block": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@react-email/code-block/-/code-block-0.2.0.tgz", - "integrity": "sha512-eIrPW9PIFgDopQU0e/OPpwCW2QWQDtNZDSsiN4sJO8KdMnWWnXJicnRfzrit5rHwFo+Y98i+w/Y5ScnBAFr1dQ==", - "license": "MIT", - "dependencies": { - "prismjs": "^1.30.0" - }, - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/code-inline": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@react-email/code-inline/-/code-inline-0.0.5.tgz", - "integrity": "sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/column": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/@react-email/column/-/column-0.0.13.tgz", - "integrity": "sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/container": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/@react-email/container/-/container-0.0.15.tgz", - "integrity": "sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/font": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@react-email/font/-/font-0.0.9.tgz", - "integrity": "sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==", - "license": "MIT", - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/head": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@react-email/head/-/head-0.0.12.tgz", - "integrity": "sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/heading": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/@react-email/heading/-/heading-0.0.15.tgz", - "integrity": "sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/hr": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@react-email/hr/-/hr-0.0.11.tgz", - "integrity": "sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/html": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@react-email/html/-/html-0.0.11.tgz", - "integrity": "sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/img": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@react-email/img/-/img-0.0.11.tgz", - "integrity": "sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/link": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.12.tgz", - "integrity": "sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/preview": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/@react-email/preview/-/preview-0.0.13.tgz", - "integrity": "sha512-F7j9FJ0JN/A4d7yr+aw28p4uX7VLWs7hTHtLo7WRyw4G+Lit6Zucq4UWKRxJC8lpsUdzVmG7aBJnKOT+urqs/w==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, "node_modules/@react-email/render": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-email/render/-/render-2.0.0.tgz", - "integrity": "sha512-rdjNj6iVzv8kRKDPFas+47nnoe6B40+nwukuXwY4FCwM7XBg6tmYr+chQryCuavUj2J65MMf6fztk1bxOUiSVA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@react-email/render/-/render-2.1.0.tgz", + "integrity": "sha512-F+zE3O6d6sW6Aj2UjvZAA17R7tJKM7kcq2mgV6k4HCT8jeLLFaVP2txMtH1lgqYFRMZ0Gxsd37q2PRyiXLXXxA==", "license": "MIT", "dependencies": { + "entities": "^4.5.0", "html-to-text": "^9.0.5", + "html5parser": "^3.0.0", "prettier": "^3.5.3" }, "engines": { - "node": ">=22.0.0" + "node": ">=20.0.0" }, "peerDependencies": { "react": "^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" } }, - "node_modules/@react-email/row": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.12.tgz", - "integrity": "sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/section": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.16.tgz", - "integrity": "sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, - "node_modules/@react-email/tailwind": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-2.0.1.tgz", - "integrity": "sha512-/xq0IDYVY7863xPY7cdI45Xoz7M6CnIQBJcQvbqN7MNVpopfH9f+mhjayV1JGfKaxlGWuxfLKhgi9T2shsnEFg==", - "license": "MIT", - "dependencies": { - "tailwindcss": "^4.1.12" - }, - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "@react-email/body": "0.2.0", - "@react-email/button": "0.2.0", - "@react-email/code-block": "0.2.0", - "@react-email/code-inline": "0.0.5", - "@react-email/container": "0.0.15", - "@react-email/heading": "0.0.15", - "@react-email/hr": "0.0.11", - "@react-email/img": "0.0.11", - "@react-email/link": "0.0.12", - "@react-email/preview": "0.0.13", - "@react-email/text": "0.1.5", - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@react-email/body": { - "optional": true - }, - "@react-email/button": { - "optional": true - }, - "@react-email/code-block": { - "optional": true - }, - "@react-email/code-inline": { - "optional": true - }, - "@react-email/container": { - "optional": true - }, - "@react-email/heading": { - "optional": true - }, - "@react-email/hr": { - "optional": true - }, - "@react-email/img": { - "optional": true - }, - "@react-email/link": { - "optional": true - }, - "@react-email/preview": { - "optional": true - } - } - }, - "node_modules/@react-email/tailwind/node_modules/tailwindcss": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", - "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", - "license": "MIT" - }, - "node_modules/@react-email/text": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@react-email/text/-/text-0.1.5.tgz", - "integrity": "sha512-o5PNHFSE085VMXayxH+SJ1LSOtGsTv+RpNKnTiJDrJUwoBu77G3PlKOsZZQHCNyD28WsQpl9v2WcJLbQudqwPg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "react": "^18.0 || ^19.0 || ^19.0.0-rc" - } - }, "node_modules/@react-router/dev": { "version": "7.18.1", "resolved": "https://registry.npmjs.org/@react-router/dev/-/dev-7.18.1.tgz", @@ -14811,43 +14219,48 @@ } }, "node_modules/@trpc/client": { - "version": "11.8.1", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-11.8.1.tgz", - "integrity": "sha512-L/SJFGanr9xGABmuDoeXR4xAdHJmsXsiF9OuH+apecJ+8sUITzVT1EPeqp0ebqA6lBhEl5pPfg3rngVhi/h60Q==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/client/-/client-11.17.0.tgz", + "integrity": "sha512-KpJBFrbKTDeVCFv/3ckL1XBBH5Yssn8hethI/rUy7GIpTj+VzjtPjykDqJpzobuVOz+d26cXCSu1t4I6MYI5Zg==", "funding": [ "https://trpc.io/sponsor" ], "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, "peerDependencies": { - "@trpc/server": "11.8.1", + "@trpc/server": "11.17.0", "typescript": ">=5.7.2" } }, "node_modules/@trpc/react-query": { - "version": "11.8.1", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-11.8.1.tgz", - "integrity": "sha512-0Vu55ld/oINb4U6nIPPi7eZMhxUop6K+4QUK90RVsfSD5r+957sM80M4c8bjh/JBZUxMFv9JOhxxlWcrgHxHow==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-11.17.0.tgz", + "integrity": "sha512-AGcl5YAF8NnhBmyJ6PqJqKb1M5VTGSoNRNqJ3orct4o4epdcg0GWhW+qT9q6gPzs/2ImIwYCdfFpgNGdZ9yLHA==", "funding": [ "https://trpc.io/sponsor" ], "license": "MIT", "peerDependencies": { "@tanstack/react-query": "^5.80.3", - "@trpc/client": "11.8.1", - "@trpc/server": "11.8.1", + "@trpc/client": "11.17.0", + "@trpc/server": "11.17.0", "react": ">=18.2.0", - "react-dom": ">=18.2.0", "typescript": ">=5.7.2" } }, "node_modules/@trpc/server": { - "version": "11.8.1", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-11.8.1.tgz", - "integrity": "sha512-P4rzZRpEL7zDFgjxK65IdyH0e41FMFfTkQkuq0BA5tKcr7E6v9/v38DEklCpoDN6sPiB1Sigy/PUEzHENhswDA==", + "version": "11.17.0", + "resolved": "https://registry.npmjs.org/@trpc/server/-/server-11.17.0.tgz", + "integrity": "sha512-jbAOUe0PpUTCYqziyu+8vYXZdDXPudZgnEhWCQ2NjKnVEjfE93RqHTt1oycZJv/HNf51YlRXfEEwSIAbb161rw==", "funding": [ "https://trpc.io/sponsor" ], "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, "peerDependencies": { "typescript": ">=5.7.2" } @@ -15423,18 +14836,6 @@ "@types/unist": "*" } }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", - "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", - "license": "MIT", - "dependencies": { - "hoist-non-react-statics": "^3.3.0" - }, - "peerDependencies": { - "@types/react": "*" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -15580,30 +14981,23 @@ "@types/node": "*" } }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT" - }, "node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/resolve": { @@ -15652,9 +15046,9 @@ "license": "MIT" }, "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", "license": "MIT" }, "node_modules/@types/ws": { @@ -16904,6 +16298,7 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -17062,6 +16457,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^5.0.0" @@ -17077,6 +16473,7 @@ "version": "2.9.2", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -17270,266 +16667,19 @@ } }, "node_modules/cmdk": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.1.tgz", - "integrity": "sha512-U6//9lQ6JvT47+6OF6Gi8BvkxYQ8SCRRSKIJkthIMsFsLZRG0cKvTtuTaefyIKMQb8rvvXy0wGdpTNq/jPtm+g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", "license": "MIT", "dependencies": { - "@radix-ui/react-dialog": "1.0.0" + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", - "integrity": "sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz", - "integrity": "sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-context": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.0.tgz", - "integrity": "sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-dialog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.0.tgz", - "integrity": "sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-context": "1.0.0", - "@radix-ui/react-dismissable-layer": "1.0.0", - "@radix-ui/react-focus-guards": "1.0.0", - "@radix-ui/react-focus-scope": "1.0.0", - "@radix-ui/react-id": "1.0.0", - "@radix-ui/react-portal": "1.0.0", - "@radix-ui/react-presence": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-slot": "1.0.0", - "@radix-ui/react-use-controllable-state": "1.0.0", - "aria-hidden": "^1.1.1", - "react-remove-scroll": "2.5.4" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.0.tgz", - "integrity": "sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/primitive": "1.0.0", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0", - "@radix-ui/react-use-escape-keydown": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz", - "integrity": "sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.0.tgz", - "integrity": "sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-primitive": "1.0.0", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", - "integrity": "sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-portal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.0.tgz", - "integrity": "sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-primitive": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-presence": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz", - "integrity": "sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0", - "@radix-ui/react-use-layout-effect": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-primitive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.0.tgz", - "integrity": "sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-slot": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-slot": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.0.tgz", - "integrity": "sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-compose-refs": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz", - "integrity": "sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz", - "integrity": "sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.0.tgz", - "integrity": "sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10", - "@radix-ui/react-use-callback-ref": "1.0.0" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz", - "integrity": "sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.13.10" - }, - "peerDependencies": { - "react": "^16.8 || ^17.0 || ^18.0" - } - }, - "node_modules/cmdk/node_modules/react-remove-scroll": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.4.tgz", - "integrity": "sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.3", - "react-style-singleton": "^2.2.1", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.0", - "use-sidecar": "^1.1.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/co-body": { @@ -18192,6 +17342,19 @@ "postcss-value-parser": "^4.0.2" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -20573,6 +19736,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -20715,6 +19879,7 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "foreground-child": "^3.3.1", @@ -20750,6 +19915,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -20759,6 +19925,7 @@ "version": "5.0.7", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -20771,6 +19938,7 @@ "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -21288,21 +20456,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, "node_modules/hono": { "version": "4.12.27", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz", @@ -21380,6 +20533,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/html5parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html5parser/-/html5parser-3.0.0.tgz", + "integrity": "sha512-iNpSopa+4YHX50UOk825tBy7MghmXHo/ZpLskBYN0kAr1xhH8GlIMk5bLRXcZlfP3AnLUcSuFMu8C4MdOUxA8A==", + "license": "MIT" + }, "node_modules/htmlparser2": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", @@ -22085,6 +21244,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^9.0.0" @@ -22100,6 +21260,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -22180,9 +21341,9 @@ } }, "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -23660,6 +22821,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -23669,12 +22836,6 @@ "node": ">= 0.6" } }, - "node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "license": "MIT" - }, "node_modules/meow": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", @@ -25505,6 +24666,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-function": "^5.0.0" @@ -26216,6 +25378,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/picospinner": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/picospinner/-/picospinner-3.0.0.tgz", + "integrity": "sha512-lGA1TNsmy2bxvRsTI2cV01kfTwKzZjnZSDmF9llYNyMHMrU4sP87lQ5taiIKm88L3cbswjl008nwyGc3WpNvzg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/pidtree": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", @@ -27209,13 +26380,10 @@ } }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, "engines": { "node": ">=0.10.0" } @@ -27254,18 +26422,23 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.2.7" } }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/react-draggable": { "version": "4.4.6", "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz", @@ -27297,6 +26470,726 @@ "react": ">= 16.8 || 18.0.0" } }, + "node_modules/react-email": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/react-email/-/react-email-6.9.0.tgz", + "integrity": "sha512-72jV+VkeeXgNWDycNDn2tIlHFLg4Hevi3pC77g63FAY1+bDgTs4b56jbZfHF1t5d+GVGb02sGS8bOwoptgvI1w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "7.29.2", + "@babel/traverse": "7.29.0", + "@react-email/render": ">=2.1.0", + "chokidar": "^4.0.3", + "commander": "^13.0.0", + "conf": "^15.0.2", + "css-tree": "3.2.1", + "debounce": "^2.0.0", + "esbuild": "^0.28.0", + "glob": "^13.0.6", + "jiti": "2.6.1", + "log-symbols": "^7.0.0", + "marked": "^15.0.12", + "mime-types": "^3.0.0", + "normalize-path": "^3.0.0", + "nypm": "0.6.6", + "picospinner": "^3.0.0", + "prismjs": "^1.30.0", + "prompts": "2.4.2", + "socket.io": "^4.8.1", + "tailwindcss": "^4.1.18", + "tsconfig-paths": "4.2.0" + }, + "bin": { + "email": "dist/cli/index.mjs" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": "^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" + } + }, + "node_modules/react-email/node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/react-email/node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/react-email/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/react-email/node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/react-email/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/react-email/node_modules/citty": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.2.tgz", + "integrity": "sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==", + "license": "MIT" + }, + "node_modules/react-email/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/react-email/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-email/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-email/node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-email/node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/react-email/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react-email/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/react-email/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-email/node_modules/nypm": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.6.tgz", + "integrity": "sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==", + "license": "MIT", + "dependencies": { + "citty": "^0.2.2", + "pathe": "^2.0.3", + "tinyexec": "^1.1.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/react-email/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/react-email/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/react-email/node_modules/tailwindcss": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", + "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "license": "MIT" + }, "node_modules/react-hook-form": { "version": "7.66.1", "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.1.tgz", @@ -27370,39 +27263,23 @@ "license": "MIT" }, "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" }, "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, "redux": { "optional": true } @@ -27777,13 +27654,10 @@ } }, "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.2" - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" }, "node_modules/reflect-metadata": { "version": "0.2.2", @@ -28113,6 +27987,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^7.0.0", @@ -28389,15 +28264,6 @@ "node": ">=16" } }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/scroll-into-view-if-needed": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", @@ -29025,18 +28891,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", @@ -30088,6 +29942,20 @@ } } }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -30961,15 +30829,6 @@ } } }, - "node_modules/use-memo-one": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", - "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/use-sidecar": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", @@ -32443,7 +32302,7 @@ "arctic": "^3.7.0", "hono": "^4.12.14", "luxon": "^3.7.2", - "react": "^18", + "react": "^19.2.7", "ts-pattern": "^5.9.0", "zod": "^3.25.76" } @@ -32455,27 +32314,9 @@ "dependencies": { "@documenso/nodemailer-resend": "5.0.0", "@documenso/tailwind-config": "*", - "@react-email/body": "0.2.0", - "@react-email/button": "0.2.0", - "@react-email/code-block": "0.2.0", - "@react-email/code-inline": "0.0.5", - "@react-email/column": "0.0.13", - "@react-email/container": "0.0.15", - "@react-email/font": "0.0.9", - "@react-email/head": "0.0.12", - "@react-email/heading": "0.0.15", - "@react-email/hr": "0.0.11", - "@react-email/html": "0.0.11", - "@react-email/img": "0.0.11", - "@react-email/link": "0.0.12", - "@react-email/preview": "0.0.13", - "@react-email/render": "2.0.0", - "@react-email/row": "0.0.12", - "@react-email/section": "0.0.16", - "@react-email/tailwind": "^2.0.1", - "@react-email/text": "0.1.5", + "@react-email/render": "2.1.0", "nodemailer": "^9.0.0", - "react-email": "^5.0.6", + "react-email": "^6.9.0", "resend": "^6.5.2" }, "devDependencies": { @@ -32483,720 +32324,6 @@ "@types/nodemailer": "^8.0.1" } }, - "packages/email/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "packages/email/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "packages/email/node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "packages/email/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, - "packages/email/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "packages/email/node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "packages/email/node_modules/log-symbols": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", - "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", - "license": "MIT", - "dependencies": { - "is-unicode-supported": "^2.0.0", - "yoctocolors": "^2.1.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "packages/email/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "packages/email/node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/ora/node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/react-email": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/react-email/-/react-email-5.0.6.tgz", - "integrity": "sha512-DEGzWpEiC3CquPEaaEJuipNT3WZ9mK58rbkpOe4Slbgyf60PLa1wONnt5a3afbBBRbNdW2aYhIvVI41yS6UIRA==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/traverse": "^7.27.0", - "chokidar": "^4.0.3", - "commander": "^13.0.0", - "conf": "^15.0.2", - "debounce": "^2.0.0", - "esbuild": "^0.25.0", - "glob": "^11.0.0", - "jiti": "2.4.2", - "log-symbols": "^7.0.0", - "mime-types": "^3.0.0", - "normalize-path": "^3.0.0", - "nypm": "0.6.0", - "ora": "^8.0.0", - "prompts": "2.4.2", - "socket.io": "^4.8.1", - "tsconfig-paths": "4.2.0" - }, - "bin": { - "email": "dist/index.js" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "packages/email/node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "packages/email/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/email/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "packages/email/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "license": "MIT", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "packages/eslint-config": { "name": "@documenso/eslint-config", "version": "0.0.0", @@ -33268,7 +32395,7 @@ "postcss-selector-parser": "^7.1.4", "posthog-js": "^1.297.2", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", "remeda": "^2.32.0", "sharp": "0.34.5", "stripe": "^12.18.0", @@ -33869,9 +32996,9 @@ "@documenso/prisma": "*", "@simplewebauthn/server": "^13.2.2", "@tanstack/react-query": "5.90.10", - "@trpc/client": "11.8.1", - "@trpc/react-query": "11.8.1", - "@trpc/server": "11.8.1", + "@trpc/client": "11.17.0", + "@trpc/react-query": "11.17.0", + "@trpc/server": "11.17.0", "@ts-rest/core": "^3.52.1", "formidable": "^3.5.4", "luxon": "^3.7.2", @@ -33897,52 +33024,25 @@ "license": "MIT", "dependencies": { "@documenso/lib": "*", - "@hello-pangea/dnd": "^16.6.0", + "@hello-pangea/dnd": "^18.0.1", "@hookform/resolvers": "^3", "@lingui/macro": "^5.6.0", "@lingui/react": "^5.6.0", - "@radix-ui/react-accordion": "^1.2.12", - "@radix-ui/react-alert-dialog": "^1.1.15", - "@radix-ui/react-aspect-ratio": "^1.1.8", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-context-menu": "^2.2.16", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-hover-card": "^1.1.15", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-menubar": "^1.1.16", - "@radix-ui/react-navigation-menu": "^1.2.14", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-progress": "^1.1.8", - "@radix-ui/react-radio-group": "^1.3.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slider": "^1.3.6", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.15", - "@radix-ui/react-toggle": "^1.1.10", - "@radix-ui/react-toggle-group": "^1.1.11", - "@radix-ui/react-tooltip": "^1.2.8", "@scure/base": "^1.2.6", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^1.2.1", - "cmdk": "^0.2.1", + "cmdk": "^1.1.1", "colord": "^2.9.3", "framer-motion": "^12.43.0", "lucide-react": "^0.554.0", "luxon": "^3.7.2", "pdfjs-dist": "5.4.296", "perfect-freehand": "^1.2.2", - "react": "^18", + "react": "^19.2.7", "react-colorful": "^5.6.1", "react-day-picker": "^8.10.1", - "react-dom": "^18", + "react-dom": "^19.2.7", "react-hook-form": "^7.66.1", "react-rnd": "^10.5.2", "remeda": "^2.32.0", @@ -33955,9 +33055,9 @@ "@documenso/tailwind-config": "*", "@documenso/tsconfig": "*", "@types/luxon": "^3.7.1", - "@types/react": "18.3.27", - "@types/react-dom": "^18", - "react": "^18", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "react": "^19.2.7", "typescript": "5.6.2" } } diff --git a/package.json b/package.json index d4382924d..6e012a297 100644 --- a/package.json +++ b/package.json @@ -48,15 +48,17 @@ }, "devDependencies": { "@biomejs/biome": "2.4.8", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "@commitlint/cli": "^20.1.0", "@commitlint/config-conventional": "^20.0.0", "@datadog/pprof": "^5.13.5", "@documenso/skia-canvas": "^3.0.8-documenso.3", "@lingui/cli": "^5.6.0", "@prisma/client": "^6.19.0", - "@trpc/client": "11.8.1", - "@trpc/react-query": "11.8.1", - "@trpc/server": "11.8.1", + "@trpc/client": "11.17.0", + "@trpc/react-query": "11.17.0", + "@trpc/server": "11.17.0", "@ts-rest/core": "^3.52.1", "@ts-rest/open-api": "^3.52.1", "@ts-rest/serverless": "^3.52.1", @@ -93,13 +95,41 @@ "@lingui/conf": "^5.6.0", "@lingui/core": "^5.6.0", "@prisma/extension-read-replicas": "^0.4.1", + "@radix-ui/react-accordion": "^1.2.16", + "@radix-ui/react-alert-dialog": "^1.1.19", + "@radix-ui/react-aspect-ratio": "^1.1.11", + "@radix-ui/react-avatar": "^1.2.2", + "@radix-ui/react-checkbox": "^1.3.7", + "@radix-ui/react-collapsible": "^1.1.16", + "@radix-ui/react-context-menu": "^2.3.3", + "@radix-ui/react-dialog": "^1.1.19", + "@radix-ui/react-dropdown-menu": "^2.1.20", + "@radix-ui/react-hover-card": "^1.1.19", + "@radix-ui/react-label": "^2.1.11", + "@radix-ui/react-menubar": "^1.1.20", + "@radix-ui/react-navigation-menu": "^1.2.18", + "@radix-ui/react-popover": "^1.1.19", + "@radix-ui/react-progress": "^1.1.12", + "@radix-ui/react-radio-group": "^1.4.3", + "@radix-ui/react-scroll-area": "^1.2.14", + "@radix-ui/react-select": "^2.3.3", + "@radix-ui/react-separator": "^1.1.11", + "@radix-ui/react-slider": "^1.4.3", + "@radix-ui/react-slot": "^1.3.0", + "@radix-ui/react-switch": "^1.3.3", + "@radix-ui/react-tabs": "^1.1.17", + "@radix-ui/react-toast": "^1.2.19", + "@radix-ui/react-toggle": "^1.1.14", + "@radix-ui/react-toggle-group": "^1.1.15", + "@radix-ui/react-tooltip": "^1.2.12", "ai": "^5.0.104", "cron-parser": "^5.5.0", "fflate": "^0.8.3", "luxon": "^3.7.2", "patch-package": "^8.0.1", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", + "react-dom": "^19.2.7", "typescript": "5.6.2", "@marsidev/react-turnstile": "^1.5.0", "zod": "^3.25.76" @@ -108,6 +138,10 @@ "lodash": "4.18.1", "pdfjs-dist": "5.4.296", "postcss": "^8.5.19", + "react": "$react", + "react-dom": "$react-dom", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "typescript": "5.6.2", "zod": "$zod", "fumadocs-mdx": { diff --git a/packages/ee/package.json b/packages/ee/package.json index 79cc3ba85..e27566f09 100644 --- a/packages/ee/package.json +++ b/packages/ee/package.json @@ -19,7 +19,7 @@ "arctic": "^3.7.0", "hono": "^4.12.14", "luxon": "^3.7.2", - "react": "^18", + "react": "^19.2.7", "ts-pattern": "^5.9.0", "zod": "^3.25.76" } diff --git a/packages/email/components.ts b/packages/email/components.ts index 3765e7190..1cb660b3c 100644 --- a/packages/email/components.ts +++ b/packages/email/components.ts @@ -1,17 +1,19 @@ -export { Body } from '@react-email/body'; -export { Button } from '@react-email/button'; -export { Column } from '@react-email/column'; -export { Container } from '@react-email/container'; -export { Font } from '@react-email/font'; -export { Head } from '@react-email/head'; -export { Heading } from '@react-email/heading'; -export { Hr } from '@react-email/hr'; -export { Html } from '@react-email/html'; -export { Img } from '@react-email/img'; -export { Link } from '@react-email/link'; -export { Preview } from '@react-email/preview'; -export { render } from '@react-email/render'; -export { Row } from '@react-email/row'; -export { Section } from '@react-email/section'; -export { Tailwind } from '@react-email/tailwind'; -export { Text } from '@react-email/text'; +export { + Body, + Button, + Column, + Container, + Font, + Head, + Heading, + Hr, + Html, + Img, + Link, + Preview, + Row, + render, + Section, + Tailwind, + Text, +} from 'react-email'; diff --git a/packages/email/package.json b/packages/email/package.json index 33426f9e5..e5ff68787 100644 --- a/packages/email/package.json +++ b/packages/email/package.json @@ -19,27 +19,9 @@ "dependencies": { "@documenso/nodemailer-resend": "5.0.0", "@documenso/tailwind-config": "*", - "@react-email/body": "0.2.0", - "@react-email/button": "0.2.0", - "@react-email/code-block": "0.2.0", - "@react-email/code-inline": "0.0.5", - "@react-email/column": "0.0.13", - "@react-email/container": "0.0.15", - "@react-email/font": "0.0.9", - "@react-email/head": "0.0.12", - "@react-email/heading": "0.0.15", - "@react-email/hr": "0.0.11", - "@react-email/html": "0.0.11", - "@react-email/img": "0.0.11", - "@react-email/link": "0.0.12", - "@react-email/preview": "0.0.13", - "@react-email/render": "2.0.0", - "@react-email/row": "0.0.12", - "@react-email/section": "0.0.16", - "@react-email/tailwind": "^2.0.1", - "@react-email/text": "0.1.5", + "@react-email/render": "2.1.0", "nodemailer": "^9.0.0", - "react-email": "^5.0.6", + "react-email": "^6.9.0", "resend": "^6.5.2" }, "devDependencies": { diff --git a/packages/lib/client-only/hooks/use-autosave.ts b/packages/lib/client-only/hooks/use-autosave.ts index 66e047482..8e2dee450 100644 --- a/packages/lib/client-only/hooks/use-autosave.ts +++ b/packages/lib/client-only/hooks/use-autosave.ts @@ -8,7 +8,7 @@ type SaveRequest = { export const useAutoSave = (onSave: (data: T) => Promise, options: { delay?: number } = {}) => { const { delay = 2000 } = options; - const saveTimeoutRef = useRef(); + const saveTimeoutRef = useRef(undefined); const saveQueueRef = useRef[]>([]); const isProcessingRef = useRef(false); diff --git a/packages/lib/client-only/providers/envelope-editor-provider.tsx b/packages/lib/client-only/providers/envelope-editor-provider.tsx index e61ed7ae0..ea49f638c 100644 --- a/packages/lib/client-only/providers/envelope-editor-provider.tsx +++ b/packages/lib/client-only/providers/envelope-editor-provider.tsx @@ -15,7 +15,7 @@ import { useToast } from '@documenso/ui/primitives/use-toast'; import { useLingui } from '@lingui/react/macro'; import { EnvelopeType, Prisma, ReadStatus, SendStatus, SigningStatus } from '@prisma/client'; import type React from 'react'; -import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react'; +import { createContext, useCallback, useContext, useMemo, useRef, useState, useSyncExternalStore } from 'react'; import { useSearchParams } from 'react-router'; import type { TDocumentEmailSettings } from '../../types/document-email'; @@ -107,7 +107,39 @@ export const EnvelopeEditorProvider = ({ const [_searchParams, setSearchParams] = useSearchParams(); - const [envelope, _setEnvelope] = useState(initialEnvelope); + /** + * The envelope is kept in a ref-backed external store instead of useState so + * that async consumers (debounced autosave callbacks, flushAutosave, resetForms) + * can synchronously read the latest value via `getEnvelope`. + * + * React subscribes to the store through useSyncExternalStore, keeping renders in + * sync without maintaining a separate copy of the state. + */ + const envelopeStoreRef = useRef(initialEnvelope); + const envelopeStoreSubscribersRef = useRef(new Set<() => void>()); + + const subscribeToEnvelopeStore = useCallback((onStoreChange: () => void) => { + envelopeStoreSubscribersRef.current.add(onStoreChange); + + return () => { + envelopeStoreSubscribersRef.current.delete(onStoreChange); + }; + }, []); + + const getEnvelope = useCallback(() => envelopeStoreRef.current, []); + + const setEnvelope = useCallback((action: React.SetStateAction) => { + const next = typeof action === 'function' ? action(envelopeStoreRef.current) : action; + + envelopeStoreRef.current = next; + + for (const onStoreChange of envelopeStoreSubscribersRef.current) { + onStoreChange(); + } + }, []); + + const envelope = useSyncExternalStore(subscribeToEnvelopeStore, getEnvelope, getEnvelope); + const [autosaveError, setAutosaveError] = useState(false); const isCscMode = IS_INSTANCE_CSC_MODE(); @@ -135,8 +167,6 @@ export const EnvelopeEditorProvider = ({ }; }, [isCscMode, providedEditorConfig]); - const envelopeRef = useRef(initialEnvelope); - const externalFlushCallbacksRef = useRef Promise>>(new Map()); const pendingMutationsRef = useRef>>(new Set()); @@ -156,14 +186,6 @@ export const EnvelopeEditorProvider = ({ }); }, []); - const setEnvelope: typeof _setEnvelope = (action) => { - _setEnvelope((prev) => { - const next = typeof action === 'function' ? action(prev) : action; - envelopeRef.current = next; - return next; - }); - }; - const isEmbedded = editorConfig.embedded !== undefined; const editorFields = useEditorFields({ @@ -192,16 +214,18 @@ export const EnvelopeEditorProvider = ({ try { let recipients: TEditorEnvelope['recipients'] = []; + const currentEnvelope = getEnvelope(); + if (!isEmbedded) { const response = await setRecipientsMutation.mutateAsync({ - envelopeId: envelope.id, - envelopeType: envelope.type, + envelopeId: currentEnvelope.id, + envelopeType: currentEnvelope.type, recipients: localRecipients, }); recipients = response.data; } else { - recipients = mapLocalRecipientsToRecipients({ envelope, localRecipients }); + recipients = mapLocalRecipientsToRecipients({ envelope: currentEnvelope, localRecipients }); } setEnvelope((prev) => ({ @@ -211,9 +235,7 @@ export const EnvelopeEditorProvider = ({ })); // Reset the local fields to ensure deleted recipient fields are removed. - editorFields.resetForm( - envelope.fields.filter((field) => recipients.some((recipient) => recipient.id === field.recipientId)), - ); + editorFields.resetForm(getEnvelope().fields); setAutosaveError(false); } catch (err) { @@ -248,16 +270,18 @@ export const EnvelopeEditorProvider = ({ try { let fields: TSetEnvelopeFieldsResponse['data'] = []; + const currentEnvelope = getEnvelope(); + if (!isEmbedded) { const response = await setFieldsMutation.mutateAsync({ - envelopeId: envelope.id, - envelopeType: envelope.type, + envelopeId: currentEnvelope.id, + envelopeType: currentEnvelope.type, fields: localFields, }); fields = response.data; } else { - fields = mapLocalFieldsToFields({ envelope, localFields }); + fields = mapLocalFieldsToFields({ envelope: currentEnvelope, localFields }); } setEnvelope((prev) => ({ @@ -309,7 +333,7 @@ export const EnvelopeEditorProvider = ({ try { const response = !isEmbedded ? await updateEnvelopeMutation.mutateAsync({ - envelopeId: envelope.id, + envelopeId: getEnvelope().id, data, meta, }) @@ -467,12 +491,14 @@ export const EnvelopeEditorProvider = ({ }; const resetForms = () => { + const currentEnvelope = getEnvelope(); + editorRecipients.resetForm({ - recipients: envelopeRef.current.recipients, - documentMeta: envelopeRef.current.documentMeta, + recipients: currentEnvelope.recipients, + documentMeta: currentEnvelope.documentMeta, }); - editorFields.resetForm(envelopeRef.current.fields); + editorFields.resetForm(currentEnvelope.fields); }; const flushAutosave = async (): Promise => { @@ -488,7 +514,7 @@ export const EnvelopeEditorProvider = ({ await Promise.allSettled(Array.from(pendingMutationsRef.current)); } - return envelopeRef.current; + return getEnvelope(); }; return ( diff --git a/packages/lib/package.json b/packages/lib/package.json index 27092f178..ab1f0a836 100644 --- a/packages/lib/package.json +++ b/packages/lib/package.json @@ -65,7 +65,7 @@ "postcss-selector-parser": "^7.1.4", "posthog-js": "^1.297.2", "posthog-node": "4.18.0", - "react": "^18", + "react": "^19.2.7", "remeda": "^2.32.0", "sharp": "0.34.5", "stripe": "^12.18.0", diff --git a/packages/trpc/package.json b/packages/trpc/package.json index f68701096..5ffcec7fb 100644 --- a/packages/trpc/package.json +++ b/packages/trpc/package.json @@ -12,9 +12,9 @@ "@documenso/prisma": "*", "@simplewebauthn/server": "^13.2.2", "@tanstack/react-query": "5.90.10", - "@trpc/client": "11.8.1", - "@trpc/react-query": "11.8.1", - "@trpc/server": "11.8.1", + "@trpc/client": "11.17.0", + "@trpc/react-query": "11.17.0", + "@trpc/server": "11.17.0", "@ts-rest/core": "^3.52.1", "formidable": "^3.5.4", "luxon": "^3.7.2", diff --git a/packages/ui/components/signing-card.tsx b/packages/ui/components/signing-card.tsx index c372a8bc7..a7f731910 100644 --- a/packages/ui/components/signing-card.tsx +++ b/packages/ui/components/signing-card.tsx @@ -35,7 +35,7 @@ export const SigningCard3D = ({ className, name, signature, signingCelebrationIm const [trackMouse, setTrackMouse] = useState(false); - const timeoutRef = useRef(); + const timeoutRef = useRef(undefined); const cardX = useMotionValue(0); const cardY = useMotionValue(0); diff --git a/packages/ui/package.json b/packages/ui/package.json index 85472a456..70f51658d 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -18,59 +18,32 @@ "@documenso/tailwind-config": "*", "@documenso/tsconfig": "*", "@types/luxon": "^3.7.1", - "@types/react": "18.3.27", - "@types/react-dom": "^18", - "react": "^18", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "react": "^19.2.7", "typescript": "5.6.2" }, "dependencies": { "@documenso/lib": "*", - "@hello-pangea/dnd": "^16.6.0", + "@hello-pangea/dnd": "^18.0.1", "@hookform/resolvers": "^3", "@lingui/macro": "^5.6.0", "@lingui/react": "^5.6.0", - "@radix-ui/react-accordion": "^1.2.12", - "@radix-ui/react-alert-dialog": "^1.1.15", - "@radix-ui/react-aspect-ratio": "^1.1.8", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-collapsible": "^1.1.12", - "@radix-ui/react-context-menu": "^2.2.16", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-hover-card": "^1.1.15", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-menubar": "^1.1.16", - "@radix-ui/react-navigation-menu": "^1.2.14", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-progress": "^1.1.8", - "@radix-ui/react-radio-group": "^1.3.8", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slider": "^1.3.6", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-switch": "^1.2.6", - "@radix-ui/react-tabs": "^1.1.13", - "@radix-ui/react-toast": "^1.2.15", - "@radix-ui/react-toggle": "^1.1.10", - "@radix-ui/react-toggle-group": "^1.1.11", - "@radix-ui/react-tooltip": "^1.2.8", "@scure/base": "^1.2.6", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^1.2.1", - "cmdk": "^0.2.1", + "cmdk": "^1.1.1", "colord": "^2.9.3", "framer-motion": "^12.43.0", "lucide-react": "^0.554.0", "luxon": "^3.7.2", "pdfjs-dist": "5.4.296", "perfect-freehand": "^1.2.2", - "react": "^18", + "react": "^19.2.7", "react-colorful": "^5.6.1", "react-day-picker": "^8.10.1", - "react-dom": "^18", + "react-dom": "^19.2.7", "react-hook-form": "^7.66.1", "react-rnd": "^10.5.2", "remeda": "^2.32.0", diff --git a/packages/ui/primitives/command.tsx b/packages/ui/primitives/command.tsx index d38038216..8ea7ebbd3 100644 --- a/packages/ui/primitives/command.tsx +++ b/packages/ui/primitives/command.tsx @@ -145,7 +145,9 @@ const CommandItem = React.forwardRef< { ) { return (
- + {field.fieldMeta.values.map((item, index) => (
- + {item.value && (
); From 05f646b326c558edfd920ff1db5836da6680b2fb Mon Sep 17 00:00:00 2001 From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com> Date: Wed, 19 Aug 2026 09:28:23 +0000 Subject: [PATCH 08/64] docs(api): document rate limit headers and 429 variants (#3133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The rate limits page claimed "No rate limit headers are currently provided" and advised a fixed 60-second wait. The middleware has been setting standard headers on every API response. ## Changes Made - Documented `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (Unix epoch seconds) on every `/api/v1`, `/api/v2`, and `/api/v2-beta` response, and `Retry-After` (seconds, min 1) on 429s. - Explained that windows are fixed epoch-aligned 1-minute buckets, so the real wait is 1–60s — clients should honor `Retry-After` instead of sleeping a fixed 60s. - Showed both 429 body shapes: the global per-IP limiter's `{ "error": ... }` vs AppError-based `code`/`message`/`statusCode`. - Covered the three distinct 429 sources: global per-IP limit, organisation windowed limits, and monthly envelope quota (which sends no rate-limit headers). - Added `/api/v2-beta/*` to the documented scope; left the verified-correct 1000/min figure and plan-limits table untouched. ## Testing Performed Docs-only change. Verified against `rate-limit-middleware.ts`, `rate-limit.ts`, `check-organisation-rate-limits.ts`, `check-monthly-quota.ts`, and the remix server router. --- .../docs/developers/api/rate-limits.mdx | 77 +++++++++++++++---- .../developers/examples/common-workflows.mdx | 7 +- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/apps/docs/content/docs/developers/api/rate-limits.mdx b/apps/docs/content/docs/developers/api/rate-limits.mdx index 95b0a68fe..878db97b6 100644 --- a/apps/docs/content/docs/developers/api/rate-limits.mdx +++ b/apps/docs/content/docs/developers/api/rate-limits.mdx @@ -11,6 +11,12 @@ Documenso enforces rate limits on all API endpoints to ensure service stability. ## HTTP Rate Limits +The rate limit applies to: + +- `/api/v1/*` +- `/api/v2/*` +- `/api/v2-beta/*` + **Limit:** 1000 requests per minute per IP address **Response:** 429 Too Many Requests @@ -19,7 +25,7 @@ Documenso enforces rate limits on all API endpoints to ensure service stability. this value, in which case you can be rate-limited before reaching the global limit. -### Rate Limit Response +### Global per-IP 429 Response ```json { @@ -27,10 +33,22 @@ Documenso enforces rate limits on all API endpoints to ensure service stability. } ``` - - No rate limit headers are currently provided. When you receive a 429 response, wait at least 60 - seconds before retrying. - +### Rate Limit Headers + +Responses from `/api/v1/*`, `/api/v2/*`, and `/api/v2-beta/*` include these headers. The only +exception is CORS preflight (`OPTIONS`) requests, which are answered before the rate limiter runs +and carry no rate limit headers: + +| Header | Description | +| ----------------------- | ---------------------------------------------------------------------- | +| `X-RateLimit-Limit` | Maximum requests allowed in the current global window | +| `X-RateLimit-Remaining` | Requests remaining in the current global window | +| `X-RateLimit-Reset` | End of the current global window, as a Unix epoch timestamp in seconds | + +A 429 response from a windowed limiter also includes `Retry-After`, in seconds, with a minimum +value of `1`. The global API limit uses fixed, epoch-aligned one-minute buckets, so the actual wait +until the next window is between 1 and 60 seconds. Honor `Retry-After` exactly instead of sleeping +for a fixed 60 seconds. See the [Retry-After handling example](/docs/developers/examples/common-workflows#error-handling-patterns). ## Resource Limits @@ -44,24 +62,55 @@ Beyond HTTP rate limits, your account has usage limits based on your subscriptio | Total Recipients | 10 | Unlimited | Unlimited | Unlimited | | Direct Templates | 3 | Unlimited | Unlimited | Unlimited | -### Error Response +### Organisation Limit 429 Responses -When you exceed a resource limit: +Organisation windowed limits and organisation monthly quotas produce 429 responses whose body +shape depends on the API version, and neither matches the global per-IP limiter's +`{ "error": "..." }` body. + +On `/api/v1/*`, the body contains only a message: ```json { - "error": "You have reached your document limit for this month. Please upgrade your plan.", - "code": "LIMIT_EXCEEDED", - "statusCode": 400 + "message": "Too many requests, please try again later. Contact support if you require higher limits." } ``` +On `/api/v2/*` and `/api/v2-beta/*`, the body is a structured error object: + +```json +{ + "message": "Too many requests, please try again later. Contact support if you require higher limits.", + "code": "TOO_MANY_REQUESTS", + "data": { + "code": "TOO_MANY_REQUESTS", + "httpStatus": 429, + "appError": { + "code": "TOO_MANY_REQUESTS", + "message": "Too many requests, please try again later. Contact support if you require higher limits." + } + } +} +``` + +Organisation windowed limit responses include the `X-RateLimit-*` headers and `Retry-After` for +their own window. Monthly quota responses carry no quota-specific rate limit headers or +`Retry-After` because the quota is not a time window; rely on the status code and message instead. + ## Error Codes -| Code | Status | Description | -| ------------------- | ------ | ----------------------------- | -| `TOO_MANY_REQUESTS` | 429 | HTTP rate limit exceeded | -| `LIMIT_EXCEEDED` | 400 | Resource usage limit exceeded | +| Code | Status | Description | +| ------------------- | ------ | ------------------------------------------------------------------ | +| `TOO_MANY_REQUESTS` | 429 | Global per-IP, organisation windowed, or monthly quota exceeded | +| `LIMIT_EXCEEDED` | 400 | Resource usage limit exceeded | + +There are three sources of `TOO_MANY_REQUESTS` responses: + +1. The global per-IP limit, returning the `{ "error": "..." }` body shown above. +2. Organisation windowed rate limits for the `api`, `document`, and `email` counters. +3. Organisation monthly quotas for the same three counters. Every authenticated API request + consumes the `api` counter, so any endpoint can return this 429 once the monthly API quota is + exhausted — not just envelope-related ones. --- diff --git a/apps/docs/content/docs/developers/examples/common-workflows.mdx b/apps/docs/content/docs/developers/examples/common-workflows.mdx index 704bf415f..5bdf32cdf 100644 --- a/apps/docs/content/docs/developers/examples/common-workflows.mdx +++ b/apps/docs/content/docs/developers/examples/common-workflows.mdx @@ -1000,9 +1000,12 @@ async function fetchWithRetry( // Retry on rate limit if (response.status === 429) { const retryAfter = response.headers.get('Retry-After'); - const delay = retryAfter ? parseInt(retryAfter) * 1000 : baseDelayMs * Math.pow(2, attempt); + // Honor Retry-After exactly; the cap only applies to the exponential fallback. + const delay = retryAfter + ? parseInt(retryAfter) * 1000 + : Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs); console.log(`Rate limited, waiting ${delay}ms...`); - await new Promise((resolve) => setTimeout(resolve, Math.min(delay, maxDelayMs))); + await new Promise((resolve) => setTimeout(resolve, delay)); continue; } From 914e325486561fe8bf23d8a949629681e2324da1 Mon Sep 17 00:00:00 2001 From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com> Date: Wed, 19 Aug 2026 09:28:40 +0000 Subject: [PATCH 09/64] docs(trpc): add openapi descriptions to envelope cancel, delete and update routes (#3134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The envelope cancel, delete, and update routes rendered without descriptions in the generated OpenAPI reference. ## Changes Made - Added route-level OpenAPI `description` to `cancel-envelope.types.ts`, `delete-envelope.types.ts`, and `update-envelope.types.ts`. - Added field-level `.describe()` calls on request schemas, matching the style of sibling envelope-router schemas (e.g. `get-envelopes-by-ids.types.ts`, `distribute-envelope.types.ts`). ## Testing Performed `npx tsc --noEmit -p packages/trpc` passes with no errors. Metadata-only change — no runtime behavior affected. --- .../envelope-router/cancel-envelope.types.ts | 5 +++-- .../envelope-router/delete-envelope.types.ts | 3 ++- .../envelope-router/update-envelope.types.ts | 20 +++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/trpc/server/envelope-router/cancel-envelope.types.ts b/packages/trpc/server/envelope-router/cancel-envelope.types.ts index 06a6637fb..59ab827c1 100644 --- a/packages/trpc/server/envelope-router/cancel-envelope.types.ts +++ b/packages/trpc/server/envelope-router/cancel-envelope.types.ts @@ -8,13 +8,14 @@ export const cancelEnvelopeMeta: TrpcRouteMeta = { method: 'POST', path: '/envelope/cancel', summary: 'Cancel envelope', + description: 'Cancel a pending envelope', tags: ['Envelope'], }, }; export const ZCancelEnvelopeRequestSchema = z.object({ - envelopeId: z.string(), - reason: z.string().optional(), + envelopeId: z.string().describe('The ID of the envelope to cancel.'), + reason: z.string().describe('The reason for cancelling the envelope.').optional(), }); export const ZCancelEnvelopeResponseSchema = ZSuccessResponseSchema; diff --git a/packages/trpc/server/envelope-router/delete-envelope.types.ts b/packages/trpc/server/envelope-router/delete-envelope.types.ts index 654d24c6d..8eaf7db9e 100644 --- a/packages/trpc/server/envelope-router/delete-envelope.types.ts +++ b/packages/trpc/server/envelope-router/delete-envelope.types.ts @@ -8,12 +8,13 @@ export const deleteEnvelopeMeta: TrpcRouteMeta = { method: 'POST', path: '/envelope/delete', summary: 'Delete envelope', + description: 'Delete an envelope', tags: ['Envelope'], }, }; export const ZDeleteEnvelopeRequestSchema = z.object({ - envelopeId: z.string(), + envelopeId: z.string().describe('The ID of the envelope to delete.'), }); export const ZDeleteEnvelopeResponseSchema = ZSuccessResponseSchema; diff --git a/packages/trpc/server/envelope-router/update-envelope.types.ts b/packages/trpc/server/envelope-router/update-envelope.types.ts index c08da086f..a4a89f9ea 100644 --- a/packages/trpc/server/envelope-router/update-envelope.types.ts +++ b/packages/trpc/server/envelope-router/update-envelope.types.ts @@ -12,24 +12,32 @@ export const updateEnvelopeMeta: TrpcRouteMeta = { method: 'POST', path: '/envelope/update', summary: 'Update envelope', + description: 'Update envelope properties and settings', tags: ['Envelope'], }, }; export const ZUpdateEnvelopeRequestSchema = z.object({ - envelopeId: z.string(), + envelopeId: z.string().describe('The ID of the envelope to update.'), data: z .object({ title: ZDocumentTitleSchema.optional(), externalId: ZDocumentExternalIdSchema.nullish(), visibility: ZDocumentVisibilitySchema.optional(), - globalAccessAuth: z.array(ZDocumentAccessAuthTypesSchema).optional(), - globalActionAuth: z.array(ZDocumentActionAuthTypesSchema).optional(), - folderId: z.string().nullish(), - templateType: z.nativeEnum(TemplateType).optional(), + globalAccessAuth: z + .array(ZDocumentAccessAuthTypesSchema) + .describe('The authentication methods required to access the envelope.') + .optional(), + globalActionAuth: z + .array(ZDocumentActionAuthTypesSchema) + .describe('The authentication methods required to sign the envelope.') + .optional(), + folderId: z.string().describe('The ID of the folder containing the envelope.').nullish(), + templateType: z.nativeEnum(TemplateType).describe('The template type.').optional(), }) + .describe('The envelope properties to update.') .optional(), - meta: ZDocumentMetaUpdateSchema.optional(), + meta: ZDocumentMetaUpdateSchema.describe('The email and signing settings to update.').optional(), }); export const ZUpdateEnvelopeResponseSchema = ZEnvelopeLiteSchema; From d42254ff52cd6257380f076022c41152b08ef60e Mon Sep 17 00:00:00 2001 From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com> Date: Wed, 19 Aug 2026 09:28:55 +0000 Subject: [PATCH 10/64] docs(api): document cancel endpoint and fix get-many body shape (#3135) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Documents API page: adds the missing Cancel Document section and fixes a fabricated request body on get-many that would fail schema validation for anyone copying the docs. ## Changes Made - Added a `## Cancel Document` section: `POST /envelope/cancel` with `{ envelopeId, reason? }`, PENDING-only (400 otherwise), not idempotent, two-stage access (404 if not visible, 401 without owner/MANAGER+), fires `DOCUMENT_CANCELLED` webhook, emails only SENT/OPENED non-CC non-rejected recipients. - Replaced the fabricated `envelopeIds: [...]` get-many body with the real nested selector: `{ "ids": { "type": "envelopeId" | "documentId" | "templateId", "ids": [...] } }` (string[] for envelopeId, number[] otherwise, 1–20 IDs). - Added the missing `### Response` for get-many (`{ "data": [...] }`) and documented silent filtering of inaccessible IDs (no 404). - Added `CANCELLED` to the status table, mermaid state diagram, transitions prose, and filter values. - Removed the nonexistent `source: "API"` value (real enum: `DOCUMENT | TEMPLATE | TEMPLATE_DIRECT_LINK`). - Fixed fabricated `pagination` wrappers to the real flat shape `{ data, count, currentPage, perPage, totalPages }`; fixed Field `id` type and mismatched code fences. - Migration guide: warned that get-many's body shape changed from `documentIds: number[]` — the breaking part of that migration. ## Testing Performed Docs-only change (plus the migration guide). Verified against the envelope-router types, `cancel-document.ts`, the cancel e2e spec, and `schema.prisma`. --- .../content/docs/developers/api/documents.mdx | 233 ++++++++++++++---- .../developers/api/migrate-to-envelopes.mdx | 4 +- 2 files changed, 189 insertions(+), 48 deletions(-) diff --git a/apps/docs/content/docs/developers/api/documents.mdx b/apps/docs/content/docs/developers/api/documents.mdx index dbe2e6a85..bd526e828 100644 --- a/apps/docs/content/docs/developers/api/documents.mdx +++ b/apps/docs/content/docs/developers/api/documents.mdx @@ -28,35 +28,62 @@ Each document contains one or more PDF files, a list of recipients, and the fiel A document object contains the following properties: -| Property | Type | Description | -| --------------- | -------------- | -------------------------------------------------------------- | -| `id` | string | Unique identifier (e.g., `envelope_abc123`) | -| `type` | string | `DOCUMENT` or `TEMPLATE` | -| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED`, or `REJECTED` | -| `title` | string | Document title | -| `source` | string | How the document was created: `DOCUMENT`, `TEMPLATE`, `API` | -| `visibility` | string | Who can view: `EVERYONE`, `ADMIN`, `MANAGER_AND_ABOVE` | -| `externalId` | string \| null | Your custom identifier for the document | -| `createdAt` | string | ISO 8601 timestamp | -| `updatedAt` | string | ISO 8601 timestamp | -| `completedAt` | string \| null | Timestamp when all recipients completed signing | -| `deletedAt` | string \| null | Timestamp if soft-deleted | -| `recipients` | array | List of recipients and their signing status | -| `fields` | array | Signature and form fields on the document | -| `envelopeItems` | array | PDF files attached to the document | -| `documentMeta` | object | Email settings, redirect URL, signing options | +| Property | Type | Description | +| ------------------- | -------------- | -------------------------------------------------------------------------------------------- | +| `id` | string | Unique identifier (e.g., `envelope_abc123`) | +| `secondaryId` | string | Legacy identifier in prefixed form (`document_123` for documents, `template_123` for templates) | +| `internalVersion` | number | Internal envelope schema version | +| `type` | string | `DOCUMENT` or `TEMPLATE` | +| `status` | string | Current status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, or `CANCELLED` | +| `title` | string | Document title | +| `source` | string | How the document was created: `DOCUMENT`, `TEMPLATE`, `TEMPLATE_DIRECT_LINK` | +| `visibility` | string | Who can view: `EVERYONE`, `ADMIN`, `MANAGER_AND_ABOVE` | +| `templateType` | string | Template visibility: `PUBLIC`, `PRIVATE`, or `ORGANISATION` (only meaningful for templates) | +| `externalId` | string \| null | Your custom identifier for the document | +| `userId` | number | ID of the user who owns the document | +| `teamId` | number | ID of the team the document belongs to | +| `folderId` | string \| null | ID of the folder containing the document | +| `templateId` | number \| null | Legacy ID of the template this document was created from | +| `authOptions` | object \| null | Access and action authentication requirements | +| `formValues` | object \| null | Pre-filled form values | +| `publicTitle` | string | Public title shown on profile and direct-link pages | +| `publicDescription` | string | Public description shown on profile and direct-link pages | +| `createdAt` | string | ISO 8601 timestamp | +| `updatedAt` | string | ISO 8601 timestamp | +| `completedAt` | string \| null | Timestamp when all recipients completed signing | +| `deletedAt` | string \| null | Timestamp if soft-deleted | +| `recipients` | array | List of recipients and their signing status | +| `fields` | array | Signature and form fields on the document | +| `envelopeItems` | array | PDF files attached to the document | +| `directLink` | object \| null | Direct-link signing configuration (`id`, `token`, `enabled`, `directTemplateRecipientId`) | +| `team` | object | Owning team (`id`, `url`) | +| `user` | object | Document owner (`id`, `name`, `email`) | +| `documentMeta` | object | Email settings, redirect URL, signing options | + +Documents created through the API have `source: "DOCUMENT"` — there is no separate `API` source value. To tag documents created by your integration, set `externalId` when creating them. ### Example Document Object ```json { "id": "envelope_abc123xyz", + "secondaryId": "document_123", + "internalVersion": 2, "type": "DOCUMENT", "status": "PENDING", - "source": "API", + "source": "DOCUMENT", "visibility": "EVERYONE", + "templateType": "PRIVATE", "title": "Service Agreement", "externalId": "contract-2025-001", + "userId": 1, + "teamId": 1, + "folderId": null, + "templateId": null, + "authOptions": null, + "formValues": null, + "publicTitle": "", + "publicDescription": "", "createdAt": "2025-01-15T10:30:00.000Z", "updatedAt": "2025-01-15T10:35:00.000Z", "completedAt": null, @@ -73,23 +100,41 @@ A document object contains the following properties: ], "fields": [ { - "id": "field_123", + "id": 123, + "secondaryId": "field_abc123", "type": "SIGNATURE", + "recipientId": 1, + "envelopeId": "envelope_abc123xyz", + "envelopeItemId": "envelope_item_xyz", "page": 1, - "positionX": 10, - "positionY": 80, - "width": 30, - "height": 5, - "recipientId": 1 + "positionX": "10", + "positionY": "80", + "width": "30", + "height": "5", + "customText": "", + "inserted": false, + "fieldMeta": null } ], "envelopeItems": [ { "id": "envelope_item_xyz", + "envelopeId": "envelope_abc123xyz", + "documentDataId": "doc_data_abc123", "title": "contract.pdf", "order": 1 } ], + "directLink": null, + "team": { + "id": 1, + "url": "your-team" + }, + "user": { + "id": 1, + "name": "Jane Smith", + "email": "jane@example.com" + }, "documentMeta": { "subject": "Please sign this document", "message": "Hi, please review and sign this agreement.", @@ -99,6 +144,8 @@ A document object contains the following properties: } ``` +Field position and size values are stored as decimals and serialized as strings in API responses. + ## List Documents Retrieve a paginated list of documents. @@ -114,7 +161,7 @@ GET /envelope | `page` | integer | Page number (default: 1) | | `perPage` | integer | Results per page (default: 10, max: 100) | | `type` | string | Filter by `DOCUMENT` or `TEMPLATE` | -| `status` | string | Filter by status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED` | +| `status` | string | Filter by status: `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, `CANCELLED` | | `source` | string | Filter by creation source | | `folderId` | string | Filter by folder ID | | `orderByColumn` | string | Sort field (only `createdAt` supported) | @@ -154,8 +201,8 @@ const response = await fetch(`${BASE_URL}/envelope`, { }, }); -const { data, pagination } = await response.json(); -console.log(`Found ${pagination.totalItems} documents`); +const { data, count } = await response.json(); +console.log(`Found ${count} documents`); // Filter by status const pendingResponse = await fetch( @@ -197,12 +244,10 @@ const pendingDocs = await pendingResponse.json(); ] } ], - "pagination": { - "page": 1, - "perPage": 10, - "totalPages": 5, - "totalItems": 42 - } + "count": 42, + "currentPage": 1, + "perPage": 10, + "totalPages": 5 } ``` @@ -628,6 +673,72 @@ The response includes signing URLs for each recipient: --- +## Cancel Document + +Cancel a pending document. This changes its status from `PENDING` to `CANCELLED`. + +``` +POST /envelope/cancel +``` + +### Request Body + +| Field | Type | Required | Description | +| ------------ | ------ | -------- | ----------------------------------- | +| `envelopeId` | string | Yes | Document ID | +| `reason` | string | No | Reason for cancelling the document | + +### Code Examples + + + +```bash +curl -X POST "https://app.documenso.com/api/v2/envelope/cancel" \ + -H "Authorization: api_xxxxxxxxxxxxxxxx" \ + -H "Content-Type: application/json" \ + -d '{ + "envelopeId": "envelope_abc123", + "reason": "The agreement is no longer needed." + }' +``` + + +```typescript +const response = await fetch('https://app.documenso.com/api/v2/envelope/cancel', { + method: 'POST', + headers: { + Authorization: 'api_xxxxxxxxxxxxxxxx', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + envelopeId: 'envelope_abc123', + reason: 'The agreement is no longer needed.', + }), +}); + +const { success } = await response.json(); +``` + + + +### Response + +```json +{ + "success": true +} +``` + +### Behavior + +- Only documents in `PENDING` status can be cancelled. Other statuses return `400`. +- Cancellation is not idempotent. Cancelling the same document again returns `400`. +- The document owner and team members with `MANAGER` or higher permissions can cancel it. Requests for documents you cannot view return `404`; requests for visible documents without sufficient permissions return `401`. +- A successful cancellation fires the `DOCUMENT_CANCELLED` webhook. +- Cancellation emails are sent only to eligible non-CC, non-rejected recipients who were sent or opened the document. + +--- + ## Delete Document Delete a document. Completed documents cannot be deleted. @@ -670,7 +781,7 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/delete', const { success } = await response.json(); -```` +``` @@ -680,7 +791,7 @@ const { success } = await response.json(); { "success": true } -```` +``` --- @@ -694,9 +805,11 @@ POST /envelope/get-many ### Request Body -| Field | Type | Required | Description | -| ------------- | ----- | -------- | --------------------- | -| `envelopeIds` | array | Yes | Array of document IDs | +| Field | Type | Required | Description | +| ---------- | ------ | -------- | ---------------------------------------------------------------------------- | +| `ids` | object | Yes | ID selector containing `type` and `ids` | +| `ids.type` | string | Yes | `envelopeId`, `documentId`, or `templateId` | +| `ids.ids` | array | Yes | 1-20 IDs: strings for `envelopeId`; numbers for `documentId` or `templateId` | ### Code Examples @@ -707,12 +820,17 @@ curl -X POST "https://app.documenso.com/api/v2/envelope/get-many" \ -H "Authorization: api_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ - "envelopeIds": ["envelope_abc123", "envelope_def456", "envelope_ghi789"] + "ids": { + "type": "envelopeId", + "ids": ["envelope_abc123", "envelope_def456", "envelope_ghi789"] + } }' ``` ```typescript +const requestedIds = ['envelope_abc123', 'envelope_def456', 'envelope_ghi789']; + const response = await fetch('https://app.documenso.com/api/v2/envelope/get-many', { method: 'POST', headers: { @@ -720,16 +838,36 @@ const response = await fetch('https://app.documenso.com/api/v2/envelope/get-many 'Content-Type': 'application/json', }, body: JSON.stringify({ - envelopeIds: ['envelope_abc123', 'envelope_def456', 'envelope_ghi789'], + ids: { + type: 'envelopeId', + ids: requestedIds, + }, }), }); -const documents = await response.json(); +const { data } = await response.json(); -```` +``` +### Response + +```json +{ + "data": [ + { + "id": "envelope_abc123", + "type": "DOCUMENT", + "status": "PENDING", + "title": "Service Agreement" + } + ] +} +``` + +The endpoint silently omits envelopes you cannot access instead of returning `404`. Compare `data.length` with `requestedIds.length` to detect omissions. + --- ## Document Statuses @@ -740,6 +878,7 @@ const documents = await response.json(); | `PENDING` | Document has been sent. Waiting for recipients to sign. | | `COMPLETED` | All recipients have signed. Document is sealed. | | `REJECTED` | A recipient rejected the document. | +| `CANCELLED` | The document was cancelled by its owner or a team member with `MANAGER` or higher permissions. | ### Status Transitions @@ -747,11 +886,13 @@ const documents = await response.json(); flowchart LR DRAFT --> PENDING --> COMPLETED PENDING --> REJECTED + PENDING --> CANCELLED ``` - **DRAFT to PENDING**: Call the distribute endpoint - **PENDING to COMPLETED**: All recipients complete their signing - **PENDING to REJECTED**: A recipient rejects the document +- **PENDING to CANCELLED**: The document owner or a team member with `MANAGER` or higher permissions cancels the document You cannot modify recipients or fields after a document moves to `PENDING` status. @@ -773,8 +914,8 @@ flowchart LR | Parameter | Values | Description | | ---------- | ------------------------------------------- | ------------------------- | | `type` | `DOCUMENT`, `TEMPLATE` | Filter by envelope type | -| `status` | `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED` | Filter by status | -| `source` | `DOCUMENT`, `TEMPLATE`, `API` | Filter by creation source | +| `status` | `DRAFT`, `PENDING`, `COMPLETED`, `REJECTED`, `CANCELLED` | Filter by status | +| `source` | `DOCUMENT`, `TEMPLATE`, `TEMPLATE_DIRECT_LINK` | Filter by creation source | | `folderId` | string | Filter by folder | ### Sorting @@ -800,10 +941,10 @@ async function getAllPendingDocuments() { }, ); - const { data, pagination } = await response.json(); + const { data, currentPage, totalPages } = await response.json(); documents.push(...data); - hasMore = page < pagination.totalPages; + hasMore = currentPage < totalPages; page++; } diff --git a/apps/docs/content/docs/developers/api/migrate-to-envelopes.mdx b/apps/docs/content/docs/developers/api/migrate-to-envelopes.mdx index 2bd5c8568..5a719e90c 100644 --- a/apps/docs/content/docs/developers/api/migrate-to-envelopes.mdx +++ b/apps/docs/content/docs/developers/api/migrate-to-envelopes.mdx @@ -119,7 +119,7 @@ Full reference in the [V2 OpenAPI reference](https://openapi.documenso.com). | ------------------------------------------------- | ----------------------------------------------------- | | `GET /api/v2/document` | `GET /api/v2/envelope` | | `GET /api/v2/document/{documentId}` | `GET /api/v2/envelope/{envelopeId}` | -| `POST /api/v2/document/get-many` | `POST /api/v2/envelope/get-many` | +| `POST /api/v2/document/get-many` | `POST /api/v2/envelope/get-many` (body changes from `documentIds: number[]` to `ids: { type: "documentId"; ids: number[] }`) | | `POST /api/v2/document/create` | `POST /api/v2/envelope/create` | | `POST /api/v2/document/create/beta` | `POST /api/v2/envelope/create` | | `POST /api/v2/document/update` | `POST /api/v2/envelope/update` | @@ -140,7 +140,7 @@ Full reference in the [V2 OpenAPI reference](https://openapi.documenso.com). | ------------------------------------- | ------------------------------------------------ | | `GET /api/v2/template` | `GET /api/v2/envelope` (with `type=TEMPLATE`) | | `GET /api/v2/template/{templateId}` | `GET /api/v2/envelope/{envelopeId}` | -| `POST /api/v2/template/get-many` | `POST /api/v2/envelope/get-many` | +| `POST /api/v2/template/get-many` | `POST /api/v2/envelope/get-many` (body changes from `templateIds: number[]` to `ids: { type: "templateId"; ids: number[] }`) | | `POST /api/v2/template/create` | `POST /api/v2/envelope/create` (`type=TEMPLATE`) | | `POST /api/v2/template/create/beta` | `POST /api/v2/envelope/create` (`type=TEMPLATE`) | | `POST /api/v2/template/update` | `POST /api/v2/envelope/update` | From 75330166cc00b29c14399bc2e391e4b4d8080c00 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Wed, 19 Aug 2026 20:34:18 +1000 Subject: [PATCH 11/64] v2.17.0 --- apps/remix/package.json | 2 +- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/remix/package.json b/apps/remix/package.json index b4e522572..cd49ddcd2 100644 --- a/apps/remix/package.json +++ b/apps/remix/package.json @@ -106,5 +106,5 @@ "vite-plugin-babel-macros": "^1.0.6", "vite-tsconfig-paths": "^5.1.4" }, - "version": "2.16.0" + "version": "2.17.0" } diff --git a/package-lock.json b/package-lock.json index c32ca8122..cf266782c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@documenso/root", - "version": "2.16.0", + "version": "2.17.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@documenso/root", - "version": "2.16.0", + "version": "2.17.0", "hasInstallScript": true, "workspaces": [ "apps/*", @@ -416,7 +416,7 @@ }, "apps/remix": { "name": "@documenso/remix", - "version": "2.16.0", + "version": "2.17.0", "dependencies": { "@cantoo/pdf-lib": "^2.5.3", "@documenso/api": "*", diff --git a/package.json b/package.json index ee0fc81fb..4770c9eec 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "apps/*", "packages/*" ], - "version": "2.16.0", + "version": "2.17.0", "scripts": { "postinstall": "patch-package", "build": "turbo run build", From ead31048962b5d1885a2a80d315684a539419523 Mon Sep 17 00:00:00 2001 From: misinierijon4-debug Date: Mon, 24 Aug 2026 08:22:48 +0200 Subject: [PATCH 12/64] fix: add type button to multiselect remove and clear buttons (#3256) --- packages/ui/primitives/multi-select-combobox.tsx | 1 + packages/ui/primitives/multiselect.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/ui/primitives/multi-select-combobox.tsx b/packages/ui/primitives/multi-select-combobox.tsx index fc867131d..5326fdaec 100644 --- a/packages/ui/primitives/multi-select-combobox.tsx +++ b/packages/ui/primitives/multi-select-combobox.tsx @@ -142,6 +142,7 @@ export function MultiSelectCombobox({ {showClearButton && !loading && (
From 1de57a9e43d73f7b3e75966c946715e69b77e94e Mon Sep 17 00:00:00 2001 From: water <672684719@qq.com> Date: Mon, 24 Aug 2026 15:05:43 +0800 Subject: [PATCH 15/64] fix(emails): remove trailing period from document pending email subject (#3213) --- .../definitions/emails/send-document-pending-email.handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts b/packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts index 3a7bf3e96..13b2b5e6e 100644 --- a/packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts +++ b/packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts @@ -93,7 +93,7 @@ export const run = async ({ payload }: { payload: TSendDocumentPendingEmailJobDe }, from: senderEmail, replyTo: replyToEmail, - subject: i18n._(msg`Waiting for others to complete signing.`), + subject: i18n._(msg`Waiting for others to complete signing`), html, text, }); From 73d58bdf31f540d7b3108c8cfbcef8345d54d2ca Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Tue, 25 Aug 2026 11:20:11 +1000 Subject: [PATCH 16/64] feat: allow admin recipient search (#3277) --- .../general/use-admin-search-categories.ts | 3 +- .../admin+/documents._index.tsx | 10 +- .../app-tests/e2e/admin/global-search.spec.ts | 95 ++++++++ .../trpc/admin/admin-find-documents.spec.ts | 226 ++++++++++++++++++ .../server-only/admin/admin-find-documents.ts | 46 +++- 5 files changed, 374 insertions(+), 6 deletions(-) create mode 100644 packages/app-tests/e2e/api/trpc/admin/admin-find-documents.spec.ts diff --git a/apps/remix/app/components/general/use-admin-search-categories.ts b/apps/remix/app/components/general/use-admin-search-categories.ts index fc950b708..547fe7afb 100644 --- a/apps/remix/app/components/general/use-admin-search-categories.ts +++ b/apps/remix/app/components/general/use-admin-search-categories.ts @@ -39,13 +39,14 @@ const ADMIN_GROUP_ICONS: Record = { /** * Admin list pages which support prefilling their search from the URL, used - * for the "View all results" links on capped groups. Teams, recipients and + * for the "View all results" links on capped groups. Teams and * subscriptions have no admin list pages. */ const ADMIN_GROUP_LIST_PATHS: Partial string>> = { document: (query) => `/admin/documents?term=${encodeURIComponent(query)}`, user: (query) => `/admin/users?search=${encodeURIComponent(query)}`, organisation: (query) => `/admin/organisations?query=${encodeURIComponent(query)}`, + recipient: (query) => `/admin/documents?term=${encodeURIComponent(`recipient:${query}`)}`, }; export type UseAdminSearchCategoriesOptions = { diff --git a/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx b/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx index 1f1bb5317..b8c84ff2b 100644 --- a/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx +++ b/apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx @@ -12,7 +12,7 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { Loader } from 'lucide-react'; -import { useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { Link, useSearchParams } from 'react-router'; import { DocumentStatus } from '~/components/general/document/document-status'; @@ -30,6 +30,12 @@ export default function AdminDocumentsPage() { const page = searchParams?.get?.('page') ? Number(searchParams.get('page')) : undefined; const perPage = searchParams?.get?.('perPage') ? Number(searchParams.get('perPage')) : undefined; + const urlTerm = searchParams?.get?.('term') ?? ''; + + useEffect(() => { + setTerm(urlTerm); + }, [urlTerm]); + const { data: findDocumentsData, isPending: isFindDocumentsLoading } = trpc.admin.document.find.useQuery( { query: debouncedTerm, @@ -131,7 +137,7 @@ export default function AdminDocumentsPage() {
setTerm(e.target.value)} /> diff --git a/packages/app-tests/e2e/admin/global-search.spec.ts b/packages/app-tests/e2e/admin/global-search.spec.ts index d8a1b5fbe..ab9f2d698 100644 --- a/packages/app-tests/e2e/admin/global-search.spec.ts +++ b/packages/app-tests/e2e/admin/global-search.spec.ts @@ -437,3 +437,98 @@ test('[ADMIN][GLOBAL_SEARCH]: over-length query skips the admin search without e expect(adminSearchRequests).toHaveLength(0); }); + +test('[ADMIN][GLOBAL_SEARCH]: capped recipients group links to the admin documents page', async ({ page }) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + const recipientPrefix = `viewall-recipient-${nanoid()}`; + + // Seed 5 documents, each with one recipient email sharing the prefix, to + // hit the 5 result cap on the recipients group. + const documents = []; + + for (let i = 0; i < 5; i++) { + documents.push( + await seedPendingDocument(sender, team.id, [`${recipientPrefix}-${i}@test.documenso.com`], { + createDocumentOptions: { title: `recipient-viewall-${nanoid()}` }, + }), + ); + } + + await apiSignin({ page, email: adminUser.email }); + + await openCommandMenu(page, ADMIN_PROMPT_PLACEHOLDER); + + await page.getByPlaceholder(ADMIN_PROMPT_PLACEHOLDER).first().fill(recipientPrefix); + + await expect(page.getByText('Global Recipients', { exact: true })).toBeVisible(); + + // Only the recipients group matches the prefix, so this is its link. + const viewAllOption = page.getByRole('option').filter({ hasText: 'View all results' }).first(); + + await expect(viewAllOption.getByRole('link')).toHaveAttribute( + 'href', + `/admin/documents?term=${encodeURIComponent(`recipient:${recipientPrefix}`)}`, + ); + + await viewAllOption.click(); + + await page.waitForURL((url) => url.pathname === '/admin/documents'); + + // The term input is prefilled with the recipient query and the matching + // documents are listed. + await expect(page.getByPlaceholder(/Search by document title/)).toHaveValue(`recipient:${recipientPrefix}`); + + for (const document of documents) { + await expect(page.getByRole('link', { name: document.title })).toBeVisible(); + } +}); + +test('[ADMIN][GLOBAL_SEARCH]: view all results updates the documents page when already on it', async ({ page }) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + const recipientPrefix = `viewall-live-${nanoid()}`; + + // Seed 5 documents with recipients matching the prefix to hit the cap, and + // one control document whose recipient does not match: with a stale + // (unfiltered) query the control would show, with the filter it must not. + const documents = []; + + for (let i = 0; i < 5; i++) { + documents.push( + await seedPendingDocument(sender, team.id, [`${recipientPrefix}-${i}@test.documenso.com`], { + createDocumentOptions: { title: `recipient-live-${nanoid()}` }, + }), + ); + } + + const controlDocument = await seedPendingDocument(sender, team.id, [`control-${nanoid()}@test.documenso.com`], { + createDocumentOptions: { title: `recipient-live-control-${nanoid()}` }, + }); + + await apiSignin({ page, email: adminUser.email }); + + // Start ON the admin documents page: the buggy state initializer has + // already run with an empty term. + await page.goto('/admin/documents'); + + await expect(page.getByPlaceholder(/Search by document title/)).toBeVisible(); + + await openCommandMenu(page, ADMIN_PROMPT_PLACEHOLDER); + + await page.getByPlaceholder(ADMIN_PROMPT_PLACEHOLDER).first().fill(recipientPrefix); + + await expect(page.getByText('Global Recipients', { exact: true })).toBeVisible(); + + await page.getByRole('option').filter({ hasText: 'View all results' }).first().click(); + + await page.waitForURL((url) => url.searchParams.get('term') === `recipient:${recipientPrefix}`); + + // The same-route navigation must update both the input and the results. + await expect(page.getByPlaceholder(/Search by document title/)).toHaveValue(`recipient:${recipientPrefix}`); + + await expect(page.getByRole('link', { name: documents[0].title })).toBeVisible(); + await expect(page.getByRole('link', { name: controlDocument.title })).toHaveCount(0); +}); diff --git a/packages/app-tests/e2e/api/trpc/admin/admin-find-documents.spec.ts b/packages/app-tests/e2e/api/trpc/admin/admin-find-documents.spec.ts new file mode 100644 index 000000000..92ea6b4cc --- /dev/null +++ b/packages/app-tests/e2e/api/trpc/admin/admin-find-documents.spec.ts @@ -0,0 +1,226 @@ +import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app'; +import { seedPendingDocument } from '@documenso/prisma/seed/documents'; +import { seedUser } from '@documenso/prisma/seed/users'; +import type { Page } from '@playwright/test'; +import { expect, test } from '@playwright/test'; +import { customAlphabet } from 'nanoid'; + +import { apiSignin } from '../../../fixtures/authentication'; + +const nanoid = customAlphabet('1234567890abcdef', 10); + +const WEBAPP_BASE_URL = NEXT_PUBLIC_WEBAPP_URL(); + +test.describe.configure({ mode: 'parallel' }); + +type AdminFindDocumentsResult = { + data: Array<{ envelopeId: string; title: string }>; + count: number; +}; + +const callAdminFindDocuments = async (page: Page, query: string) => { + const inputParam = encodeURIComponent(JSON.stringify({ json: { query, page: 1, perPage: 20 } })); + const url = `${WEBAPP_BASE_URL}/api/trpc/admin.document.find?input=${inputParam}`; + + const res = await page.context().request.get(url); + + return { + res, + result: res.ok() + ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + ((await res.json()).result.data.json as AdminFindDocumentsResult) + : null, + }; +}; + +// ─── Access control ────────────────────────────────────────────────────────── + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: non-admin user is rejected with 401', async ({ page }) => { + const { user: nonAdminUser } = await seedUser({ isAdmin: false }); + + await apiSignin({ page, email: nonAdminUser.email }); + + const { res } = await callAdminFindDocuments(page, 'recipient:anything'); + + expect(res.ok()).toBeFalsy(); + expect(res.status()).toBe(401); +}); + +// ─── recipient: prefix ─────────────────────────────────────────────────────── + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix matches by recipient email', async ({ page }) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + const recipientEmail = `recipient-find-${nanoid()}@test.documenso.com`; + + const matchingDocument = await seedPendingDocument(sender, team.id, [recipientEmail], { + createDocumentOptions: { title: `recipient-find-match-${nanoid()}` }, + }); + + const otherDocument = await seedPendingDocument(sender, team.id, [`other-${nanoid()}@test.documenso.com`], { + createDocumentOptions: { title: `recipient-find-other-${nanoid()}` }, + }); + + await apiSignin({ page, email: adminUser.email }); + + const { res, result } = await callAdminFindDocuments(page, `recipient:${recipientEmail}`); + + expect(res.ok()).toBeTruthy(); + expect(result?.count).toBe(1); + expect(result?.data.map((document) => document.envelopeId)).toContain(matchingDocument.id); + expect(result?.data.map((document) => document.envelopeId)).not.toContain(otherDocument.id); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix matches by recipient name case-insensitively', async ({ + page, +}) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + const recipientName = `recipient-name-${nanoid()}`; + const { user: recipientUser } = await seedUser({ name: recipientName }); + + const matchingDocument = await seedPendingDocument(sender, team.id, [recipientUser], { + createDocumentOptions: { title: `recipient-name-match-${nanoid()}` }, + }); + + await apiSignin({ page, email: adminUser.email }); + + // Query the uppercased name: matching must be case-insensitive. + const { res, result } = await callAdminFindDocuments(page, `recipient:${recipientName.toUpperCase()}`); + + expect(res.ok()).toBeTruthy(); + expect(result?.count).toBe(1); + expect(result?.data.map((document) => document.envelopeId)).toContain(matchingDocument.id); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix with empty value returns no results', async ({ page }) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + + await apiSignin({ page, email: adminUser.email }); + + const emptyValueSearch = await callAdminFindDocuments(page, 'recipient:'); + + expect(emptyValueSearch.res.ok()).toBeTruthy(); + expect(emptyValueSearch.result?.data).toEqual([]); + expect(emptyValueSearch.result?.count).toBe(0); + + // Whitespace-only values are treated the same as empty. + const whitespaceValueSearch = await callAdminFindDocuments(page, 'recipient: '); + + expect(whitespaceValueSearch.res.ok()).toBeTruthy(); + expect(whitespaceValueSearch.result?.data).toEqual([]); + expect(whitespaceValueSearch.result?.count).toBe(0); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix with no matches returns no results', async ({ page }) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + + await apiSignin({ page, email: adminUser.email }); + + const { res, result } = await callAdminFindDocuments(page, 'recipient:zzzz-no-such-recipient-9x7q'); + + expect(res.ok()).toBeTruthy(); + expect(result?.data).toEqual([]); + expect(result?.count).toBe(0); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix with numeric value matches by exact recipient ID', async ({ + page, +}) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + const matchingDocument = await seedPendingDocument(sender, team.id, [`recipient-id-${nanoid()}@test.documenso.com`], { + createDocumentOptions: { title: `recipient-id-match-${nanoid()}` }, + }); + + const recipient = matchingDocument.recipients[0]; + + // A decoy whose recipient email contains the ID as text: an exact ID lookup + // must exclude it, while an accidental "ID or contains" match would not. + const decoyDocument = await seedPendingDocument( + sender, + team.id, + [`decoy-${recipient.id}-${nanoid()}@test.documenso.com`], + { + createDocumentOptions: { title: `recipient-id-decoy-${nanoid()}` }, + }, + ); + + await apiSignin({ page, email: adminUser.email }); + + const { res, result } = await callAdminFindDocuments(page, `recipient:${recipient.id}`); + + expect(res.ok()).toBeTruthy(); + expect(result?.count).toBe(1); + expect(result?.data.map((document) => document.envelopeId)).toContain(matchingDocument.id); + expect(result?.data.map((document) => document.envelopeId)).not.toContain(decoyDocument.id); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix with nonexistent recipient ID returns no results', async ({ + page, +}) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + + await apiSignin({ page, email: adminUser.email }); + + // Int4 max - 1: a valid ID-shaped number that no autoincrement recipient + // sequence will plausibly reach, and that no other test seeds as text. + const { res, result } = await callAdminFindDocuments(page, 'recipient:2147483646'); + + expect(res.ok()).toBeTruthy(); + expect(result?.data).toEqual([]); + expect(result?.count).toBe(0); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: recipient prefix with oversized number falls back to text search', async ({ + page, +}) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + const { user: sender, team } = await seedUser(); + + // 99999999999999 exceeds Int4, so it cannot be an ID lookup: it must be + // treated as text (and must not 500). + const oversizedNumber = '99999999999999'; + + const matchingDocument = await seedPendingDocument( + sender, + team.id, + [`${oversizedNumber}-${nanoid()}@test.documenso.com`], + { + createDocumentOptions: { title: `recipient-oversized-${nanoid()}` }, + }, + ); + + await apiSignin({ page, email: adminUser.email }); + + const { res, result } = await callAdminFindDocuments(page, `recipient:${oversizedNumber}`); + + expect(res.ok()).toBeTruthy(); + expect(result?.data.map((document) => document.envelopeId)).toContain(matchingDocument.id); +}); + +test('[ADMIN][TRPC][FIND_DOCUMENTS]: user and team prefixes with oversized numbers return no results', async ({ + page, +}) => { + const { user: adminUser } = await seedUser({ isAdmin: true }); + + await apiSignin({ page, email: adminUser.email }); + + // 99999999999999 exceeds Int4, so it can never be a valid user or team ID. + // The ID schema must reject it so the query returns empty instead of + // overflowing Postgres and erroring. + const userSearch = await callAdminFindDocuments(page, 'user:99999999999999'); + + expect(userSearch.res.ok()).toBeTruthy(); + expect(userSearch.result?.data).toEqual([]); + expect(userSearch.result?.count).toBe(0); + + const teamSearch = await callAdminFindDocuments(page, 'team:99999999999999'); + + expect(teamSearch.res.ok()).toBeTruthy(); + expect(teamSearch.result?.data).toEqual([]); + expect(teamSearch.result?.count).toBe(0); +}); diff --git a/packages/lib/server-only/admin/admin-find-documents.ts b/packages/lib/server-only/admin/admin-find-documents.ts index 994422ba7..4643daed8 100644 --- a/packages/lib/server-only/admin/admin-find-documents.ts +++ b/packages/lib/server-only/admin/admin-find-documents.ts @@ -10,7 +10,13 @@ export interface AdminFindDocumentsOptions { perPage?: number; } -const ZPositiveIntegerSchema = z.coerce.number().int().positive(); +const MAX_POSTGRES_INT = 2147483647; + +/** + * IDs are Postgres int4 columns: values above the range can never be valid + * IDs and would make Prisma throw on overflow, so the schema rejects them. + */ +const ZPositiveIntegerSchema = z.coerce.number().int().positive().max(MAX_POSTGRES_INT); const emptyResponse = { data: [], @@ -58,7 +64,41 @@ export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: Admi } } - if (query && query?.startsWith('envelope_')) { + if (query?.startsWith('recipient:')) { + const recipientQuery = query.slice('recipient:'.length).trim(); + + if (recipientQuery.length === 0) { + return emptyResponse; + } + + // Bare numeric values are exact recipient ID lookups, consistent with the + // user: and team: prefixes. Oversized numbers cannot be IDs and fall back + // to the text search, mirroring the admin global search. + const parsedRecipientId = ZPositiveIntegerSchema.safeParse(recipientQuery); + + if (/^\d+$/.test(recipientQuery) && parsedRecipientId.success) { + termFilters = { + recipients: { + some: { + id: parsedRecipientId.data, + }, + }, + }; + } else { + termFilters = { + recipients: { + some: { + OR: [ + { email: { contains: recipientQuery, mode: 'insensitive' } }, + { name: { contains: recipientQuery, mode: 'insensitive' } }, + ], + }, + }, + }; + } + } + + if (query?.startsWith('envelope_')) { termFilters = { id: { equals: query, @@ -66,7 +106,7 @@ export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: Admi }; } - if (query && query?.startsWith('document_')) { + if (query?.startsWith('document_')) { termFilters = { secondaryId: { equals: query, From 10f2b800258079199c2f17324dc93a93de0e15c5 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Tue, 25 Aug 2026 11:07:31 +0300 Subject: [PATCH 17/64] feat: last used column for api tokens (#3230) --- .../t.$teamUrl+/settings.tokens.tsx | 17 ++++++++++++ .../public-api/get-api-token-by-token.ts | 26 +++++++++++++++++++ .../server-only/public-api/get-api-tokens.ts | 1 + .../migration.sql | 2 ++ packages/prisma/schema.prisma | 21 ++++++++------- .../api-token-router/get-api-tokens.types.ts | 1 + 6 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 packages/prisma/migrations/20260818081941_add_api_token_last_used_property/migration.sql diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx index 239137d0b..548933f01 100644 --- a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx @@ -68,6 +68,20 @@ export default function ApiTokensPage() { return i18n.date(row.original.expires); }, }, + { + header: t`Last Used`, + cell: ({ row }) => { + if (!row.original.lastUsedAt) { + return ( + + Never + + ); + } + + return {i18n.date(row.original.lastUsedAt)}; + }, + }, { header: t`Actions`, cell: ({ row }) => ( @@ -146,6 +160,9 @@ export default function ApiTokensPage() { + + + diff --git a/packages/lib/server-only/public-api/get-api-token-by-token.ts b/packages/lib/server-only/public-api/get-api-token-by-token.ts index d25b9b902..abfab5ec3 100644 --- a/packages/lib/server-only/public-api/get-api-token-by-token.ts +++ b/packages/lib/server-only/public-api/get-api-token-by-token.ts @@ -1,9 +1,12 @@ import { prisma } from '@documenso/prisma'; import { AppError, AppErrorCode } from '../../errors/app-error'; +import { logger } from '../../utils/logger'; import { hashString } from '../auth/hash'; import { assertOrganisationRatesAndLimits } from '../rate-limit/assert-organisation-rates-and-limits'; +const LAST_USED_AT_UPDATE_INTERVAL = 60_000; // 1 minute + type GetApiTokenByTokenOptions = { token: string; @@ -96,6 +99,29 @@ export const getApiTokenByToken = async ({ token, bypassRateLimit = false }: Get }); } + // Only update the lastUsedAt after X amount of time has passed to reduce + // the number of writes to the database + if (!apiToken.lastUsedAt || apiToken.lastUsedAt.getTime() + LAST_USED_AT_UPDATE_INTERVAL < Date.now()) { + void prisma.apiToken + .updateMany({ + where: { + id: apiToken.id, + // Optimistic guard: skip if another request beat us + lastUsedAt: apiToken.lastUsedAt, + }, + data: { + lastUsedAt: new Date(), + }, + }) + .catch((err) => { + logger.warn({ + msg: 'Failed to update API token lastUsedAt', + apiTokenId: apiToken.id, + err, + }); + }); + } + return { ...apiToken, user, diff --git a/packages/lib/server-only/public-api/get-api-tokens.ts b/packages/lib/server-only/public-api/get-api-tokens.ts index 06e014a10..a97ba809d 100644 --- a/packages/lib/server-only/public-api/get-api-tokens.ts +++ b/packages/lib/server-only/public-api/get-api-tokens.ts @@ -22,6 +22,7 @@ export const getApiTokens = async ({ userId, teamId }: GetApiTokensOptions) => { name: true, createdAt: true, expires: true, + lastUsedAt: true, }, orderBy: { createdAt: 'desc', diff --git a/packages/prisma/migrations/20260818081941_add_api_token_last_used_property/migration.sql b/packages/prisma/migrations/20260818081941_add_api_token_last_used_property/migration.sql new file mode 100644 index 000000000..9b9f88927 --- /dev/null +++ b/packages/prisma/migrations/20260818081941_add_api_token_last_used_property/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "ApiToken" ADD COLUMN "lastUsedAt" TIMESTAMP(3); diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 06be2eed9..13768e34f 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -220,16 +220,17 @@ enum ApiTokenAlgorithm { } model ApiToken { - id Int @id @default(autoincrement()) - name String - token String @unique - algorithm ApiTokenAlgorithm @default(SHA512) - expires DateTime? - createdAt DateTime @default(now()) - userId Int? - user User? @relation(fields: [userId], references: [id], onDelete: Cascade) - teamId Int - team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) + id Int @id @default(autoincrement()) + name String + token String @unique + algorithm ApiTokenAlgorithm @default(SHA512) + expires DateTime? + createdAt DateTime @default(now()) + lastUsedAt DateTime? + userId Int? + user User? @relation(fields: [userId], references: [id], onDelete: Cascade) + teamId Int + team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) } enum SubscriptionStatus { diff --git a/packages/trpc/server/api-token-router/get-api-tokens.types.ts b/packages/trpc/server/api-token-router/get-api-tokens.types.ts index 6a690066d..c3f06d916 100644 --- a/packages/trpc/server/api-token-router/get-api-tokens.types.ts +++ b/packages/trpc/server/api-token-router/get-api-tokens.types.ts @@ -9,6 +9,7 @@ export const ZGetApiTokensResponseSchema = z.array( name: true, createdAt: true, expires: true, + lastUsedAt: true, }), ); From dd08da7ea722a8fd9aca1b0c876eb624c039f8f8 Mon Sep 17 00:00:00 2001 From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com> Date: Tue, 25 Aug 2026 08:29:24 +0000 Subject: [PATCH 18/64] refactor(trpc): use ts-pattern for envelope document-data resolution (#3222) --- .../server/envelope-router/create-envelope.ts | 19 ++++++------------- .../envelope-router/sign-envelope-field.ts | 7 +++---- .../server/envelope-router/use-envelope.ts | 18 +++++------------- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/packages/trpc/server/envelope-router/create-envelope.ts b/packages/trpc/server/envelope-router/create-envelope.ts index c721ad31e..1a5038a10 100644 --- a/packages/trpc/server/envelope-router/create-envelope.ts +++ b/packages/trpc/server/envelope-router/create-envelope.ts @@ -8,6 +8,7 @@ import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-reques import { putPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server'; import { EnvelopeType } from '@prisma/client'; import type { Logger } from 'pino'; +import { match, P } from 'ts-pattern'; import { insertFormValuesInPdf } from '../../../lib/server-only/pdf/insert-form-values-in-pdf'; import { authenticatedProcedure } from '../trpc'; @@ -148,19 +149,11 @@ export const createEnvelopeRouteCaller = async ({ accessAuth: recipient.accessAuth, actionAuth: recipient.actionAuth, fields: recipient.fields?.map((field) => { - let documentDataId: string | undefined; - - if (typeof field.identifier === 'string') { - documentDataId = envelopeItems.find((item) => item.title === field.identifier)?.documentDataId; - } - - if (typeof field.identifier === 'number') { - documentDataId = envelopeItems.at(field.identifier)?.documentDataId; - } - - if (field.identifier === undefined) { - documentDataId = envelopeItems.at(0)?.documentDataId; - } + const documentDataId = match(field.identifier) + .with(P.string, (title) => envelopeItems.find((item) => item.title === title)?.documentDataId) + .with(P.number, (index) => envelopeItems.at(index)?.documentDataId) + .with(undefined, () => envelopeItems.at(0)?.documentDataId) + .exhaustive(); if (!documentDataId) { throw new AppError(AppErrorCode.NOT_FOUND, { diff --git a/packages/trpc/server/envelope-router/sign-envelope-field.ts b/packages/trpc/server/envelope-router/sign-envelope-field.ts index ef1828fee..54f4129a5 100644 --- a/packages/trpc/server/envelope-router/sign-envelope-field.ts +++ b/packages/trpc/server/envelope-router/sign-envelope-field.ts @@ -39,8 +39,8 @@ export const signEnvelopeFieldRoute = procedure const field = await prisma.field.findFirst({ where: { id: fieldId, - recipient: { - ...(recipient.role === RecipientRole.ASSISTANT + recipient: + recipient.role === RecipientRole.ASSISTANT ? { signingStatus: { not: SigningStatus.SIGNED, @@ -52,8 +52,7 @@ export const signEnvelopeFieldRoute = procedure } : { id: recipient.id, - }), - }, + }, }, include: { envelope: { diff --git a/packages/trpc/server/envelope-router/use-envelope.ts b/packages/trpc/server/envelope-router/use-envelope.ts index 769e598fa..608b430d9 100644 --- a/packages/trpc/server/envelope-router/use-envelope.ts +++ b/packages/trpc/server/envelope-router/use-envelope.ts @@ -6,6 +6,7 @@ import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/ import { putNormalizedPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server'; import { formatSigningLink } from '@documenso/lib/utils/recipients'; import { EnvelopeType } from '@prisma/client'; +import { match, P } from 'ts-pattern'; import { authenticatedProcedure } from '../trpc'; import { useEnvelopeMeta, ZUseEnvelopeRequestSchema, ZUseEnvelopeResponseSchema } from './use-envelope.types'; @@ -87,20 +88,11 @@ export const useEnvelopeRoute = authenticatedProcedure // Map custom document data using identifiers const customDocumentDataMapped = customDocumentData?.map((mapping) => { - let documentDataId: string | undefined; - // Find the uploaded file by identifier - if (typeof mapping.identifier === 'string') { - documentDataId = uploadedFiles.find((file) => file.name === mapping.identifier)?.documentDataId; - } - - if (typeof mapping.identifier === 'number') { - documentDataId = uploadedFiles.at(mapping.identifier)?.documentDataId; - } - - if (mapping.identifier === undefined) { - documentDataId = uploadedFiles.at(0)?.documentDataId; - } + const documentDataId = match(mapping.identifier) + .with(P.string, (name) => uploadedFiles.find((file) => file.name === name)?.documentDataId) + .with(P.number, (index) => uploadedFiles.at(index)?.documentDataId) + .exhaustive(); if (!documentDataId) { throw new AppError(AppErrorCode.NOT_FOUND, { From e532843aa646211fab99bd122beaba67efd11bfc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:37:33 +1000 Subject: [PATCH 19/64] chore: extract translations (#3171) --- packages/lib/translations/de/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/en/web.po | 236 ++++++++++++++++++++++--- packages/lib/translations/es/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/fr/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/it/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/ja/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/ko/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/nl/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/pl/web.po | 234 +++++++++++++++++++++--- packages/lib/translations/pt-BR/web.po | 232 +++++++++++++++++++++--- packages/lib/translations/zh/web.po | 234 +++++++++++++++++++++--- 11 files changed, 2299 insertions(+), 275 deletions(-) diff --git a/packages/lib/translations/de/web.po b/packages/lib/translations/de/web.po index 9c319219b..2a41636e1 100644 --- a/packages/lib/translations/de/web.po +++ b/packages/lib/translations/de/web.po @@ -312,6 +312,12 @@ msgstr "{0}-Feld" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} hat Sie eingeladen, das Dokument \"{1}\" {recipientActionVerb}." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} im Namen von \"{teamName}\" hat dich eingeladen, {0}<0/>\" msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} im Namen von \"{teamName}\" hat Sie eingeladen, das Dokument {documentName} {action}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {Sie können nicht mehr als # Zugangsschlüssel haben.} other {Sie können nicht mehr als # Zugangsschlüssel haben.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} hat Sie eingeladen, {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "Konto entkoppelt" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Bestätigung" @@ -1818,10 +1836,6 @@ msgstr "Beim automatischen Signieren des Dokuments ist ein Fehler aufgetreten, e msgid "An error occurred while cancelling the documents." msgstr "Beim Stornieren der Dokumente ist ein Fehler aufgetreten." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Beim Abschließen des Dokuments ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Ein Fehler ist aufgetreten, während das Dokument aus der Vorlage erstellt wurde." @@ -2455,6 +2469,10 @@ msgstr "Eckenradius-Größe in REM-Einheiten (z. B. 0.5rem)." msgid "Bottom" msgstr "Unten" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Markenfarben" @@ -2988,6 +3006,14 @@ msgstr "Durch Kommas getrennte Liste von E-Mail-Domains, die von der Registrieru msgid "Communication" msgstr "Kommunikation" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Vergleichen Sie alle Pläne und Funktionen im Detail" @@ -3174,6 +3200,11 @@ msgstr "Zustimmung zu elektronischen Transaktionen" msgid "Contact Information" msgstr "Kontaktinformationen" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Vertrieb hier kontaktieren" @@ -3182,6 +3213,10 @@ msgstr "Vertrieb hier kontaktieren" msgid "Contact us" msgstr "Kontaktieren Sie uns" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Inhalt" @@ -3234,6 +3269,10 @@ msgstr "Fahre fort, indem du das Dokument ansiehst." msgid "Continue to login" msgstr "Weiter zum Login" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Steuert, wie lange Empfänger Zeit haben, die Signatur abzuschließen, bevor das Dokument abläuft. Nach dem Ablauf können Empfänger das Dokument nicht mehr unterschreiben." @@ -4335,6 +4374,10 @@ msgstr "Die Authentifizierung für den Dokumentenzugriff wurde aktualisiert" msgid "Document All" msgstr "Dokument Alle" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "Dokument genehmigt" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Dokument storniert" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Dokument ins Team verschoben" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Dokument steht nicht mehr zur Unterschrift zur Verfügung" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Dokumentpräferenzen aktualisiert" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Dokument abgelehnt" @@ -4978,6 +5031,10 @@ msgstr "Z. B. 100" msgid "e.g. Resend (free plans)" msgstr "z. B. Resend (kostenlose Tarife)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Geben Sie hier Ihren Text ein" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Unternehmen" @@ -5562,7 +5621,6 @@ msgstr "Umschlag aktualisiert" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Umschlag aktualisiert" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Kontaktdaten werden extrahiert" msgid "Failed" msgstr "Fehlgeschlagen" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Das Dokument konnte nicht abgeschlossen werden. Bitte versuchen Sie es erneut." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Dokument konnte nicht erstellt werden. Bitte versuchen Sie es erneut." @@ -6147,6 +6200,10 @@ msgstr "Links generieren" msgid "German" msgstr "Deutsch" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Hallo, {userName} <0>({userEmail})" msgid "Hide" msgstr "Ausblenden" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Lizenzschlüssel ausblenden" @@ -6789,6 +6850,10 @@ msgstr "Es ist momentan nicht Ihre Runde zum Unterschreiben. Bitte schauen Sie b msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "Es ist derzeit nicht deine Reihe zu unterschreiben. Du erhältst eine E-Mail mit Anweisungen, sobald es deine Reihe ist, das Dokument zu unterschreiben." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italienisch" @@ -6907,6 +6972,10 @@ msgstr "Zuletzt aktualisiert am" msgid "Last used" msgstr "Zuletzt verwendet" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Verwalten" msgid "Manage {0}'s profile" msgstr "Verwalten Sie das Profil von {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Verwalten Sie ein benutzerdefiniertes SSO-Login-Portal für Ihre Organisation." @@ -7531,6 +7601,10 @@ msgstr "Name ist erforderlich" msgid "Name Settings" msgstr "Einstellungen für Namen" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "Muss sehen" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Niemals" @@ -7944,6 +8019,10 @@ msgstr "Sobald Ihre Vorlage eingerichtet ist, teilen Sie den Link überall, wo S msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Eines der Dokumente im aktuellen Paket hat eine Signaturrolle, die mit der aktuellen Signiererfahrung nicht kompatibel ist." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Nur Administratoren können auf das Dokument zugreifen und es anzeigen" @@ -8127,6 +8206,7 @@ msgstr "Organisationsrolle" msgid "Organisation Settings" msgstr "Organisationseinstellungen" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Bitte wählen Sie mindestens ein Mitglied aus, das zum Team hinzugefügt msgid "Please select how you'd like to receive your verification code." msgstr "Bitte wählen Sie, wie Sie Ihren Verifizierungscode erhalten möchten." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Bitte versuchen Sie eine andere Domain." @@ -8859,6 +8944,10 @@ msgstr "Öffentliche Vorlage" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Öffentliche Vorlagen sind mit Ihrem öffentlichen Profil verbunden. Änderungen an öffentlichen Vorlagen erscheinen auch in Ihrem öffentlichen Profil." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Schnellaktionen" @@ -9187,6 +9276,10 @@ msgstr "Weiterleitung" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "Antwort-Header" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Seien Sie versichert, Ihr Dokument ist streng vertraulich und wird niemals geteilt. Nur Ihre Unterzeichnungserfahrung wird hervorgehoben. Teilen Sie Ihre personalisierte Unterschriftkarte, um Ihre Unterschrift zu präsentieren!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Eingeschränkter Zugriff" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Suche nach Anspruchs-ID oder Name" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Nach Dokumenttitel, team:123 oder user:123 suchen" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Dokument senden" msgid "Send Document" msgstr "Dokument senden" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Dokumente im Namen des Teams über die E-Mail-Adresse senden" @@ -10079,6 +10180,10 @@ msgstr "Dokumente im Namen des Teams über die E-Mail-Adresse senden" msgid "Send documents to recipients immediately" msgstr "Dokumente sofort an Empfänger senden" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Umschlag senden" @@ -10125,6 +10230,14 @@ msgstr "Absender" msgid "Sender reported" msgstr "Absender gemeldet" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Zurücksetzungs-E-Mail wird gesendet..." @@ -10145,6 +10258,10 @@ msgstr "Gesendet" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sitzung widerrufen" @@ -10250,6 +10367,7 @@ msgstr "Nutzung mit Kontingenten anzeigen" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Signiert" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Unterzeichner" @@ -10485,6 +10607,10 @@ msgstr "Unterzeichne für" msgid "Signing in..." msgstr "Anmeldung..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "Die Registrierung ist derzeit deaktiviert oder für Ihre E-Mail-Domain n msgid "Since {0}" msgstr "Seit {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Website Banner" @@ -10556,6 +10686,10 @@ msgstr "Überspringen" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "Einige Unterzeichner haben noch kein Unterschriftsfeld zugewiesen bekomm #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Einige Unterzeichner haben noch kein Unterschriftsfeld zugewiesen bekomm #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Einige Unterzeichner haben noch kein Unterschriftsfeld zugewiesen bekomm #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Etwas ist schief gelaufen" @@ -11137,6 +11269,7 @@ msgstr "Team-URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Dieses Dokument kann nicht wiederhergestellt werden. Wenn du den Grund für zukünftige Dokumente anfechten möchtest, kontaktiere bitte den Support." @@ -11920,6 +12057,10 @@ msgstr "Dieses Dokument konnte derzeit nicht dupliziert werden. Bitte versuche e msgid "This document could not be saved as a template at this time. Please try again." msgstr "Dieses Dokument konnte derzeit nicht als Vorlage gespeichert werden. Bitte versuchen Sie es erneut." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Dieses Dokument wurde vom Eigentümer storniert und steht anderen nicht msgid "This document has been cancelled by the owner." msgstr "Dieses Dokument wurde vom Eigentümer storniert." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Dieses Dokument wurde von einem Empfänger abgelehnt" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Dieses Dokument wurde von allen Empfängern unterschrieben" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Dieses Dokument hat zu viele Empfänger. Bitte entfernen Sie einige Empfänger oder kontaktieren Sie den Support, wenn Sie mehr benötigen." @@ -11958,6 +12111,10 @@ msgstr "Dieses Dokument ist in Ihrem Documenso-Konto verfügbar. Dort können Si msgid "This document is currently a draft and has not been sent" msgstr "Dieses Dokument ist momentan ein Entwurf und wurde nicht gesendet" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Dieses Dokument verwendet Altfeld-Integration, wir empfehlen die Verwendung der neuen Methode für genauere Ergebnisse." @@ -12673,6 +12830,18 @@ msgstr "Unbegrenzte Dokumente, API und mehr" msgid "Unlink" msgstr "Verknüpfung aufheben" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Lösen" @@ -12846,6 +13015,10 @@ msgstr "Upgrade" msgid "Upgrade <0>{0} to {planName}" msgstr "<0>{0} auf {planName} aktualisieren" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Aktualisieren Sie Ihren Tarif, um mehr Dokumente hochzuladen" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "Warten auf andere" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Warten auf andere, um die Unterzeichnung abzuschließen." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "Wir konnten Ihr öffentliches Profil nicht auf öffentlich setzen. Bitte msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "Wir konnten die Zwei-Faktor-Authentifizierung für Ihr Konto nicht einrichten. Bitte stellen Sie sicher, dass Sie den Code korrekt eingegeben haben und versuchen Sie es erneut." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "Wir konnten dieses Dokument zurzeit nicht einreichen. Bitte versuchen Sie es später erneut." @@ -13830,6 +14001,11 @@ msgstr "Willkommen zurück, wir freuen uns, Sie zu haben." msgid "Welcome back! Here's an overview of your account." msgstr "Willkommen zurück! Hier ist ein Überblick über Ihr Konto." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Willkommen bei {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Zustimmung widerrufen" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Schreiben Sie eine Beschreibung, die in Ihrem öffentlichen Profil angezeigt wird" @@ -14157,10 +14337,6 @@ msgstr "Sie können wählen, ob das Profil für die öffentliche Ansicht aktivie msgid "You can copy and share these links to recipients so they can action the document." msgstr "Sie können diese Links kopieren und mit den Empfängern teilen, damit sie das Dokument bearbeiten können." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Sie können den Zugriff so aktivieren, dass alle Organisationsmitglieder standardmäßig Zugriff auf dieses Team haben." @@ -14924,6 +15100,10 @@ msgstr "Ihr Kuvert wurde erfolgreich verteilt." msgid "Your envelope has been resent successfully." msgstr "Ihr Kuvert wurde erfolgreich erneut gesendet." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Ihr Name" @@ -15057,6 +15237,10 @@ msgstr "Ihre Unterzeichnungsautorisierung ist abgelaufen, bevor die Signatur ang msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Ihr Signaturzertifikat ist ungültig, abgelaufen oder es fehlt ein erforderlicher Schlüssel. Wenden Sie sich an Ihren Administrator oder Unterzeichnungsanbieter, um Unterstützung zu erhalten." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "Ihre Authentifizierung beim Unterzeichnungsanbieter ist fehlgeschlagen" diff --git a/packages/lib/translations/en/web.po b/packages/lib/translations/en/web.po index 6fb1dbfe5..980c3cfae 100644 --- a/packages/lib/translations/en/web.po +++ b/packages/lib/translations/en/web.po @@ -307,6 +307,12 @@ msgstr "{0} field" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} has invited you to {recipientActionVerb} the document \"{1}\"." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "{0} has invited you to sign this document." + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -429,6 +435,10 @@ msgstr "{inviterName} on behalf of \"{teamName}\" has invited you to {0}<0/>\"{d msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" @@ -509,8 +519,12 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} has invited you to {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" -msgstr "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "{totalVisibleCount, plural, one {# item} other {# items}}" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" +msgstr "{totalVisibleCount, plural, one {# result} other {# results}}" #: packages/lib/utils/document-audit-logs.ts msgid "{user} added a field" @@ -1216,6 +1230,10 @@ msgstr "Account Settings" msgid "Account unlinked" msgstr "Account unlinked" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "Accounts are automatically added to your organisation on sign-in" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Acknowledgment" @@ -1813,10 +1831,6 @@ msgstr "An error occurred while auto-signing the document, some fields may not b msgid "An error occurred while cancelling the documents." msgstr "An error occurred while cancelling the documents." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "An error occurred while completing the document. Please try again." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "An error occurred while creating document from template." @@ -2450,6 +2464,10 @@ msgstr "Border radius size in REM units (e.g. 0.5rem)." msgid "Bottom" msgstr "Bottom" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "Brand accent" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Brand Colours" @@ -2983,6 +3001,14 @@ msgstr "Comma-separated list of email domains to block from signing up." msgid "Communication" msgstr "Communication" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "Company details" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "Company details and website in email footers" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Compare all plans and features in detail" @@ -3169,6 +3195,11 @@ msgstr "Consent to Electronic Transactions" msgid "Contact Information" msgstr "Contact Information" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "Contact Sales" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Contact sales here" @@ -3177,6 +3208,10 @@ msgstr "Contact sales here" msgid "Contact us" msgstr "Contact us" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "Contact your organisation owner to upgrade plans." + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Content" @@ -3229,6 +3264,10 @@ msgstr "Continue by viewing the document." msgid "Continue to login" msgstr "Continue to login" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "Continue with SSO" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." @@ -4330,6 +4369,10 @@ msgstr "Document access auth updated" msgid "Document All" msgstr "Document All" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "Document already completed" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "Document already signed" @@ -4340,6 +4383,7 @@ msgstr "Document Approved" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Document cancelled" @@ -4514,10 +4558,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Document moved to team" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "Document no longer available" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Document no longer available to sign" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "Document not ready" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4545,6 +4597,7 @@ msgstr "Document preferences updated" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Document rejected" @@ -4973,6 +5026,10 @@ msgstr "E.g. 100" msgid "e.g. Resend (free plans)" msgstr "e.g. Resend (free plans)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "Easy DNS setup with auto-generated DKIM and SPF records" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5491,6 +5548,8 @@ msgid "Enter your text here" msgstr "Enter your text here" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5557,7 +5616,6 @@ msgstr "Envelope updated" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5568,7 +5626,6 @@ msgstr "Envelope updated" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5738,10 +5795,6 @@ msgstr "Extracting contact details" msgid "Failed" msgstr "Failed" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Failed to complete the document. Please try again." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Failed to create document. Please try again." @@ -6142,6 +6195,10 @@ msgstr "Generate Links" msgid "German" msgstr "German" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6374,6 +6431,10 @@ msgstr "Hi, {userName} <0>({userEmail})" msgid "Hide" msgstr "Hide" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "Hide field" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Hide license key" @@ -6784,6 +6845,10 @@ msgstr "It's currently not your turn to sign. Please check back soon as this doc msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "It's not your turn to sign yet" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italian" @@ -6902,6 +6967,10 @@ msgstr "Last updated at" msgid "Last used" msgstr "Last used" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "Last Used" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7100,6 +7169,7 @@ msgstr "Manage" msgid "Manage {0}'s profile" msgstr "Manage {0}'s profile" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Manage a custom SSO login portal for your organisation." @@ -7526,6 +7596,10 @@ msgstr "Name is required" msgid "Name Settings" msgstr "Name Settings" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "Named senders with defaults per team, template or document" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "Navigate" @@ -7553,6 +7627,7 @@ msgstr "Needs to view" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Never" @@ -7939,6 +8014,10 @@ msgstr "Once your template is set up, share the link anywhere you want. The pers msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Only admins can access and view the document" @@ -8122,6 +8201,7 @@ msgstr "Organisation Role" msgid "Organisation Settings" msgstr "Organisation Settings" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8668,6 +8748,11 @@ msgstr "Please select at least one member to add to the team." msgid "Please select how you'd like to receive your verification code." msgstr "Please select how you'd like to receive your verification code." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "Please sign: Example.pdf" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Please try a different domain." @@ -8854,6 +8939,10 @@ msgstr "Public Template" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "Put your own brand on every document you send. Branding is available on the Teams plan and above." + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Quick Actions" @@ -9182,6 +9271,10 @@ msgstr "Redirecting" msgid "Redirecting to {0}..." msgstr "Redirecting to {0}..." +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "Redirecting to your identity provider" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9550,6 +9643,10 @@ msgstr "Response Headers" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "Restrict sign-ins by email domain and choose the default role" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Restricted Access" @@ -9711,8 +9808,8 @@ msgid "Search by claim ID or name" msgstr "Search by claim ID or name" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Search by document title, team:123 or user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "Search by document title, recipient:123, team:123 or user:123" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10066,6 +10163,10 @@ msgstr "Send document" msgid "Send Document" msgstr "Send Document" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "Send documents from your own domain. Email domains are available on the Enterprise plan." + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Send documents on behalf of the team using the email address" @@ -10074,6 +10175,10 @@ msgstr "Send documents on behalf of the team using the email address" msgid "Send documents to recipients immediately" msgstr "Send documents to recipients immediately" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "Send emails to recipients from your domain" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Send Envelope" @@ -10120,6 +10225,14 @@ msgstr "Sender" msgid "Sender reported" msgstr "Sender reported" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "Sending from app.documenso.com" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "Sending from your domain" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Sending Reset Email..." @@ -10140,6 +10253,10 @@ msgstr "Sent" msgid "Sent this period" msgstr "Sent this period" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "Separate branding per team" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Session revoked" @@ -10245,6 +10362,7 @@ msgstr "Show usage with quotas" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10416,6 +10534,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Signed" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "Signed in" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Signer" @@ -10480,6 +10602,10 @@ msgstr "Signing for" msgid "Signing in..." msgstr "Signing in..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "Signing link expired" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10532,6 +10658,10 @@ msgstr "Signup is currently disabled or not available for your email domain." msgid "Since {0}" msgstr "Since {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "Single sign-on" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Site Banner" @@ -10551,6 +10681,10 @@ msgstr "Skip" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "Some fields were not saved" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "Some searches failed — results may be incomplete." @@ -10572,7 +10706,6 @@ msgstr "Some signers have not been assigned a signature field. Please assign at #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10582,8 +10715,6 @@ msgstr "Some signers have not been assigned a signature field. Please assign at #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10606,6 +10737,7 @@ msgstr "Some signers have not been assigned a signature field. Please assign at #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Something went wrong" @@ -11132,6 +11264,7 @@ msgstr "Team URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11887,6 +12020,10 @@ msgstr "This direct link template cannot be used because one or more signers do msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." @@ -11915,6 +12052,10 @@ msgstr "This document could not be duplicated at this time. Please try again." msgid "This document could not be saved as a template at this time. Please try again." msgstr "This document could not be saved as a template at this time. Please try again." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "This document has already been completed and no further signatures can be added." + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11933,14 +12074,26 @@ msgstr "This document has been cancelled by the owner and is no longer available msgid "This document has been cancelled by the owner." msgstr "This document has been cancelled by the owner." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "This document has been rejected by a recipient" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "This document has been rejected by a recipient and can no longer be signed." + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "This document has been signed by all recipients" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "This document has not been sent for signing yet. Please wait for the sender to send it before signing." + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "This document has too many recipients. Please remove some recipients or contact support if you need more." @@ -11953,6 +12106,10 @@ msgstr "This document is available in your Documenso account. You can view more msgid "This document is currently a draft and has not been sent" msgstr "This document is currently a draft and has not been sent" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." @@ -12668,6 +12825,18 @@ msgstr "Unlimited documents, API and more" msgid "Unlink" msgstr "Unlink" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "Unlock Branding Preferences" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "Unlock Email Domains" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "Unlock the Organisation SSO Portal" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Unpin" @@ -12841,6 +13010,10 @@ msgstr "Upgrade" msgid "Upgrade <0>{0} to {planName}" msgstr "Upgrade <0>{0} to {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "Upgrade Plan" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Upgrade your plan to upload more documents" @@ -13327,8 +13500,8 @@ msgid "Waiting for others" msgstr "Waiting for others" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Waiting for others to complete signing." +msgid "Waiting for others to complete signing" +msgstr "Waiting for others to complete signing" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13657,9 +13830,7 @@ msgstr "We were unable to set your public profile to public. Please try again." msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "We were unable to submit this document at this time. Please try again later." @@ -13825,6 +13996,11 @@ msgstr "Welcome back, we are lucky to have you." msgid "Welcome back! Here's an overview of your account." msgstr "Welcome back! Here's an overview of your account." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "Welcome to {0}" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Welcome to {organisationName}" @@ -13902,6 +14078,10 @@ msgstr "Withdrawing Consent" msgid "Within limit" msgstr "Within limit" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "Works with any OIDC provider — Okta, Entra ID, Google and more" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Write a description to display on your public profile" @@ -14152,10 +14332,6 @@ msgstr "You can choose to enable or disable the profile for public view." msgid "You can copy and share these links to recipients so they can action the document." msgstr "You can copy and share these links to recipients so they can action the document." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "You can enable access to allow all organisation members to access this team by default." @@ -14919,6 +15095,10 @@ msgstr "Your envelope has been distributed successfully." msgid "Your envelope has been resent successfully." msgstr "Your envelope has been resent successfully." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "Your logo on signing pages and emails" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Your Name" @@ -15052,6 +15232,10 @@ msgstr "Your signing authorisation expired before the signature could be applied msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "Your signing link has expired. Please contact the sender to request a new one." + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "Your signing provider authentication failed" diff --git a/packages/lib/translations/es/web.po b/packages/lib/translations/es/web.po index 83127e45b..8e7abeac6 100644 --- a/packages/lib/translations/es/web.po +++ b/packages/lib/translations/es/web.po @@ -312,6 +312,12 @@ msgstr "Campo {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} te ha invitado a {recipientActionVerb} el documento \"{1}\"." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} en nombre de \"{teamName}\" te ha invitado a {0}<0/>\"{doc msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} en nombre de \"{teamName}\" te ha invitado a {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {No puedes tener más de # clave de acceso.} other {No puedes tener más de # claves de acceso.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} te ha invitado a {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "Cuenta desvinculada" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Reconocimiento" @@ -1818,10 +1836,6 @@ msgstr "Se produjo un error al firmar automáticamente el documento, es posible msgid "An error occurred while cancelling the documents." msgstr "Se produjo un error al cancelar los documentos." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Se produjo un error al completar el documento. Inténtalo de nuevo." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Ocurrió un error al crear el documento a partir de la plantilla." @@ -2455,6 +2469,10 @@ msgstr "Tamaño del radio del borde en unidades REM (p. ej., 0.5rem)." msgid "Bottom" msgstr "Fondo" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Colores de la marca" @@ -2988,6 +3006,14 @@ msgstr "Lista de dominios de correo electrónico, separados por comas, que se bl msgid "Communication" msgstr "Comunicación" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Compara todos los planes y características en detalle" @@ -3174,6 +3200,11 @@ msgstr "Consentimiento para Transacciones Electrónicas" msgid "Contact Information" msgstr "Información de Contacto" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Contactar ventas aquí" @@ -3182,6 +3213,10 @@ msgstr "Contactar ventas aquí" msgid "Contact us" msgstr "Contáctanos" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Contenido" @@ -3234,6 +3269,10 @@ msgstr "Continúa viendo el documento." msgid "Continue to login" msgstr "Continuar con el inicio de sesión" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Controla cuánto tiempo tienen los destinatarios para completar la firma antes de que el documento caduque. Después de la caducidad, los destinatarios ya no podrán firmar el documento." @@ -4335,6 +4374,10 @@ msgstr "Se actualizó la autenticación de acceso al documento" msgid "Document All" msgstr "Documentar Todo" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "Documento Aprobado" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Documento cancelado" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Documento movido al equipo" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "El documento ya no está disponible para firmar" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Preferencias del documento actualizadas" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Documento rechazado" @@ -4978,6 +5031,10 @@ msgstr "Ej.: 100" msgid "e.g. Resend (free plans)" msgstr "p. ej., Resend (planes gratuitos)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Ingresa tu texto aquí" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5562,7 +5621,6 @@ msgstr "Sobre actualizado" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Sobre actualizado" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Extrayendo datos de contacto" msgid "Failed" msgstr "Error" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "No se pudo completar el documento. Inténtalo de nuevo." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "No se pudo crear el documento. Inténtalo de nuevo." @@ -6147,6 +6200,10 @@ msgstr "Generar enlaces" msgid "German" msgstr "Alemán" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Hola, {userName} <0>({userEmail})" msgid "Hide" msgstr "Ocultar" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Ocultar clave de licencia" @@ -6789,6 +6850,10 @@ msgstr "Actualmente no es tu turno para firmar. Por favor, vuelve pronto ya que msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "Actualmente no es tu turno para firmar. Recibirás un correo electrónico con instrucciones una vez sea tu turno para firmar el documento." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italiano" @@ -6907,6 +6972,10 @@ msgstr "Última actualización el" msgid "Last used" msgstr "Último uso" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Gestionar" msgid "Manage {0}'s profile" msgstr "Gestionar el perfil de {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Administra un portal de inicio de sesión SSO personalizado para tu organización." @@ -7531,6 +7601,10 @@ msgstr "Se requiere el nombre" msgid "Name Settings" msgstr "Configuración de Nombre" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "Necesita ver" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Nunca" @@ -7944,6 +8019,10 @@ msgstr "Una vez que su plantilla esté configurada, comparta el enlace donde des msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Uno de los documentos en el paquete actual tiene un rol de firma que no es compatible con la experiencia de firma actual." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Solo los administradores pueden acceder y ver el documento" @@ -8127,6 +8206,7 @@ msgstr "Rol de Organización" msgid "Organisation Settings" msgstr "Configuraciones de la Organización" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Por favor, selecciona al menos un miembro para añadir al equipo." msgid "Please select how you'd like to receive your verification code." msgstr "Por favor, selecciona cómo te gustaría recibir tu código de verificación." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Por favor, intenta con un dominio diferente." @@ -8859,6 +8944,10 @@ msgstr "Plantilla pública" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Las plantillas públicas están conectadas a tu perfil público. Cualquier modificación a las plantillas públicas también aparecerá en tu perfil público." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Acciones rápidas" @@ -9187,6 +9276,10 @@ msgstr "Redireccionando" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "Encabezados de respuesta" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Ten la seguridad de que tu documento es estrictamente confidencial y nunca será compartido. Solo se destacará tu experiencia de firma. ¡Comparte tu tarjeta de firma personalizada para mostrar tu firma!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Acceso restringido" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Buscar por ID de reclamo o nombre" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Buscar por título del documento, team:123 o user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Enviar documento" msgid "Send Document" msgstr "Enviar documento" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Enviar documentos en nombre del equipo usando la dirección de correo electrónico" @@ -10079,6 +10180,10 @@ msgstr "Enviar documentos en nombre del equipo usando la dirección de correo el msgid "Send documents to recipients immediately" msgstr "Enviar documentos a los destinatarios inmediatamente" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Enviar sobre (envelope)" @@ -10125,6 +10230,14 @@ msgstr "Remitente" msgid "Sender reported" msgstr "Remitente denunciado" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Enviando correo de restablecimiento..." @@ -10145,6 +10258,10 @@ msgstr "Enviado" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sesión revocada" @@ -10250,6 +10367,7 @@ msgstr "Mostrar uso con cuotas" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Firmado" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Firmante" @@ -10485,6 +10607,10 @@ msgstr "Firmando para" msgid "Signing in..." msgstr "Iniciando sesión..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "El registro está deshabilitado actualmente o no está disponible para e msgid "Since {0}" msgstr "Desde {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Banner del sitio" @@ -10556,6 +10686,10 @@ msgstr "Omitir" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "Algunos firmantes no han sido asignados a un campo de firma. Asigne al m #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Algunos firmantes no han sido asignados a un campo de firma. Asigne al m #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Algunos firmantes no han sido asignados a un campo de firma. Asigne al m #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Algo salió mal" @@ -11137,6 +11269,7 @@ msgstr "URL del equipo" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Este documento no se puede recuperar, si deseas impugnar la razón para documentos futuros, por favor contacta con el soporte." @@ -11920,6 +12057,10 @@ msgstr "Este documento no se pudo duplicar en este momento. Por favor, inténtal msgid "This document could not be saved as a template at this time. Please try again." msgstr "Este documento no se pudo guardar como plantilla en este momento. Por favor, inténtelo de nuevo." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Este documento ha sido cancelado por el propietario y ya no está dispon msgid "This document has been cancelled by the owner." msgstr "Este documento ha sido cancelado por el propietario." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Este documento ha sido rechazado por un destinatario" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Este documento ha sido firmado por todos los destinatarios" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Este documento tiene demasiados destinatarios. Elimina algunos destinatarios o contacta con el soporte si necesitas más." @@ -11958,6 +12111,10 @@ msgstr "Este documento está disponible en tu cuenta de Documenso. Puedes ver m msgid "This document is currently a draft and has not been sent" msgstr "Este documento es actualmente un borrador y no ha sido enviado" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Este documento está usando inserción de campos heredada, recomendamos usar el nuevo método para resultados más precisos." @@ -12673,6 +12830,18 @@ msgstr "Documentos ilimitados, API y más" msgid "Unlink" msgstr "Desvincular" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Desanclar" @@ -12846,6 +13015,10 @@ msgstr "Actualizar" msgid "Upgrade <0>{0} to {planName}" msgstr "Actualizar <0>{0} a {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Actualiza tu plan para cargar más documentos" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "Esperando a otros" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Esperando a que otros completen la firma." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "No pudimos configurar tu perfil público como público. Por favor, inté msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "No pudimos configurar la autenticación de dos factores para tu cuenta. Asegúrate de haber ingresado correctamente tu código e inténtalo de nuevo." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "No pudimos enviar este documento en este momento. Por favor, inténtalo de nuevo más tarde." @@ -13830,6 +14001,11 @@ msgstr "Bienvenido de nuevo, somos afortunados de tenerte." msgid "Welcome back! Here's an overview of your account." msgstr "¡Bienvenido de nuevo! Aquí tienes un resumen de tu cuenta." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Bienvenido a {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Retirar Consentimiento" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Escribe una descripción para mostrar en tu perfil público" @@ -14157,10 +14337,6 @@ msgstr "Puedes elegir habilitar o deshabilitar el perfil para vista pública." msgid "You can copy and share these links to recipients so they can action the document." msgstr "Puede copiar y compartir estos enlaces con los destinatarios para que puedan gestionar el documento." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Puedes habilitar el acceso para permitir que todos los miembros de la organización accedan a este equipo por defecto." @@ -14924,6 +15100,10 @@ msgstr "Su sobre ha sido distribuido exitosamente." msgid "Your envelope has been resent successfully." msgstr "Su sobre ha sido reenviado exitosamente." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Tu nombre" @@ -15057,6 +15237,10 @@ msgstr "Tu autorización de firma caducó antes de que se pudiera aplicar la fir msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Tu certificado de firma no es válido, ha caducado o le falta una clave obligatoria. Ponte en contacto con tu administrador o con tu proveedor de firma para obtener ayuda." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "Falló tu autenticación con el proveedor de firma" diff --git a/packages/lib/translations/fr/web.po b/packages/lib/translations/fr/web.po index bb1cea408..085e2fe1a 100644 --- a/packages/lib/translations/fr/web.po +++ b/packages/lib/translations/fr/web.po @@ -312,6 +312,12 @@ msgstr "champ {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} vous a invité à {recipientActionVerb} le document \"{1}\"." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} représentant \"{teamName}\" vous a invité à {0}<0/>\"{d msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} représentant \"{teamName}\" vous a invité à {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {Vous ne pouvez pas avoir plus de # clé d'accès.} other {Vous ne pouvez pas avoir plus de # clés d'accès.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} vous a invité à {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "Compte dissocié" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Reconnaissance" @@ -1818,10 +1836,6 @@ msgstr "Une erreur est survenue lors de la signature automatique du document, ce msgid "An error occurred while cancelling the documents." msgstr "Une erreur s’est produite lors de l’annulation des documents." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Une erreur s'est produite lors de la finalisation du document. Veuillez réessayer." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Une erreur est survenue lors de la création du document à partir d'un modèle." @@ -2455,6 +2469,10 @@ msgstr "Taille du rayon de la bordure en unités REM (par ex. 0.5rem)." msgid "Bottom" msgstr "Bas" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Couleurs de la marque" @@ -2988,6 +3006,14 @@ msgstr "Liste de domaines de messagerie, séparés par des virgules, à bloquer msgid "Communication" msgstr "Communication" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Comparez tous les plans et fonctionnalités en détail" @@ -3174,6 +3200,11 @@ msgstr "Consentement aux transactions électroniques" msgid "Contact Information" msgstr "Coordonnées" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Contactez le service commercial ici" @@ -3182,6 +3213,10 @@ msgstr "Contactez le service commercial ici" msgid "Contact us" msgstr "Contactez-nous" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Contenu" @@ -3234,6 +3269,10 @@ msgstr "Continuer en consultant le document." msgid "Continue to login" msgstr "Continuer vers la connexion" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Détermine combien de temps les destinataires disposent pour terminer la signature avant l’expiration du document. Après expiration, les destinataires ne peuvent plus signer le document." @@ -4335,6 +4374,10 @@ msgstr "L'authentification d'accès au document a été mise à jour" msgid "Document All" msgstr "Document Tout" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "Document Approuvé" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Document annulé" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Document déplacé vers l'équipe" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Document non disponible pour signature" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Préférences de document mises à jour" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Document rejeté" @@ -4978,6 +5031,10 @@ msgstr "Par ex. 100" msgid "e.g. Resend (free plans)" msgstr "p. ex. Resend (offres gratuites)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Entrez votre texte ici" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Entreprise" @@ -5562,7 +5621,6 @@ msgstr "Enveloppe mise à jour" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Enveloppe mise à jour" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Extraction des coordonnées" msgid "Failed" msgstr "Échec" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Échec de la finalisation du document. Veuillez réessayer." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Échec de la création du document. Veuillez réessayer." @@ -6147,6 +6200,10 @@ msgstr "Générer des liens" msgid "German" msgstr "Allemand" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Bonjour, {userName} <0>({userEmail})" msgid "Hide" msgstr "Cacher" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Masquer la clé de licence" @@ -6789,6 +6850,10 @@ msgstr "Ce n'est actuellement pas votre tour de signer. Veuillez revenir bientô msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "Ce n'est actuellement pas votre tour de signer. Vous recevrez un e-mail avec des instructions une fois que ce sera votre tour de signer le document." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italien" @@ -6907,6 +6972,10 @@ msgstr "Dernière mise à jour à" msgid "Last used" msgstr "Dernière utilisation" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Gérer" msgid "Manage {0}'s profile" msgstr "Gérer le profil de {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Gérez un portail de connexion SSO personnalisé pour votre organisation." @@ -7531,6 +7601,10 @@ msgstr "Le nom est requis" msgid "Name Settings" msgstr "Paramètres du nom" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "Nécessite une visualisation" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Jamais" @@ -7944,6 +8019,10 @@ msgstr "Une fois votre modèle configuré, partagez le lien où vous le souhaite msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "L'un des documents du paquet actuel a un rôle de signature qui n'est pas compatible avec l'expérience de signature actuelle." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Seules les administrateurs peuvent accéder et voir le document" @@ -8127,6 +8206,7 @@ msgstr "Rôle de l'organisation" msgid "Organisation Settings" msgstr "Paramètres de l'organisation" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Veuillez sélectionner au moins un membre à ajouter à l’équipe." msgid "Please select how you'd like to receive your verification code." msgstr "Veuillez sélectionner le moyen par lequel vous souhaitez recevoir votre code de vérification." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Veuillez essayer un autre domaine." @@ -8859,6 +8944,10 @@ msgstr "Modèle Public" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Les modèles publics sont connectés à votre profil public. Toute modification apportée aux modèles publics apparaîtra également dans votre profil public." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Actions Rapides" @@ -9187,6 +9276,10 @@ msgstr "Redirection" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "En-têtes de réponse" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Soyez assuré, votre document eststrictement confidentiel et ne sera jamais partagé. Seule votre expérience de signature sera mise en avant. Partagez votre carte de signature personnalisée pour mettre en valeur votre signature !" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Accès restreint" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Recherche par ID de réclamation ou nom" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Rechercher par titre de document, team:123 ou user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Envoyer le document" msgid "Send Document" msgstr "Envoyer le document" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Envoyer des documents au nom de l'équipe en utilisant l'adresse e-mail" @@ -10079,6 +10180,10 @@ msgstr "Envoyer des documents au nom de l'équipe en utilisant l'adresse e-mail" msgid "Send documents to recipients immediately" msgstr "Envoyer les documents aux destinataires immédiatement" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Envoyer l’enveloppe" @@ -10125,6 +10230,14 @@ msgstr "Expéditeur" msgid "Sender reported" msgstr "Expéditeur signalé" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Envoi de l'e-mail de réinitialisation..." @@ -10145,6 +10258,10 @@ msgstr "Envoyé" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Session révoquée" @@ -10250,6 +10367,7 @@ msgstr "Afficher l’utilisation avec quotas" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Signé" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Signataire" @@ -10485,6 +10607,10 @@ msgstr "Signé pour" msgid "Signing in..." msgstr "Connexion en cours..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "L’inscription est actuellement désactivée ou non disponible pour vot msgid "Since {0}" msgstr "Depuis {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Bannière du site" @@ -10556,6 +10686,10 @@ msgstr "Ignorer" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "Certains signataires n'ont pas été assignés à un champ de signature. #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Certains signataires n'ont pas été assignés à un champ de signature. #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Certains signataires n'ont pas été assignés à un champ de signature. #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Quelque chose a mal tourné" @@ -11137,6 +11269,7 @@ msgstr "URL de l'équipe" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Ce document ne peut pas être récupéré, si vous souhaitez contester la raison des documents futurs, veuillez contacter le support." @@ -11920,6 +12057,10 @@ msgstr "Ce document n'a pas pu être dupliqué pour le moment. Veuillez réessay msgid "This document could not be saved as a template at this time. Please try again." msgstr "Ce document n'a pas pu être enregistré comme modèle pour le moment. Veuillez réessayer." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Ce document a été annulé par le propriétaire et n'est plus disponibl msgid "This document has been cancelled by the owner." msgstr "Ce document a été annulé par le propriétaire." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Ce document a été rejeté par un destinataire" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Ce document a été signé par tous les destinataires" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Ce document comporte trop de destinataires. Veuillez en supprimer certains ou contacter l’assistance si vous avez besoin d’en ajouter davantage." @@ -11958,6 +12111,10 @@ msgstr "Ce document est disponible dans votre compte Documenso. Vous pouvez y vo msgid "This document is currently a draft and has not been sent" msgstr "Ce document est actuellement un brouillon et n'a pas été envoyé" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Ce document utilise l'insertion de champ héritée, il est recommandé d'utiliser la nouvelle méthode d'insertion pour des résultats plus précis." @@ -12673,6 +12830,18 @@ msgstr "Documents illimités, API et plus" msgid "Unlink" msgstr "Délier" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Détacher" @@ -12846,6 +13015,10 @@ msgstr "Améliorer" msgid "Upgrade <0>{0} to {planName}" msgstr "Mettre à niveau <0>{0} vers {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Mettez à niveau votre plan pour importer plus de documents" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "En attente des autres" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "En attente que d'autres terminent la signature." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "Nous n'avons pas pu définir votre profil public comme public. Veuillez msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "Nous n'avons pas pu configurer l'authentification à deux facteurs pour votre compte. Veuillez vous assurer que vous avez correctement entré votre code et réessayez." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "Nous n'avons pas pu soumettre ce document pour le moment. Veuillez réessayer plus tard." @@ -13830,6 +14001,11 @@ msgstr "Bon retour, nous sommes heureux de vous retrouver." msgid "Welcome back! Here's an overview of your account." msgstr "Bon retour ! Voici un aperçu de votre compte." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Bienvenue chez {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Retrait du consentement" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Écrivez une description à afficher sur votre profil public" @@ -14157,10 +14337,6 @@ msgstr "Vous pouvez choisir d'activer ou de désactiver le profil pour l'afficha msgid "You can copy and share these links to recipients so they can action the document." msgstr "Vous pouvez copier et partager ces liens avec les destinataires afin qu'ils puissent agir sur le document." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Vous pouvez autoriser l'accès par défaut, permettant à tous les membres de l'organisation d'accéder à cette équipe." @@ -14924,6 +15100,10 @@ msgstr "Votre enveloppe a été distribuée avec succès." msgid "Your envelope has been resent successfully." msgstr "Votre enveloppe a été renvoyée avec succès." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Votre nom" @@ -15057,6 +15237,10 @@ msgstr "Votre autorisation de signature a expiré avant que la signature ne puis msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Votre certificat de signature est invalide, expiré ou ne contient pas une clé requise. Contactez votre administrateur ou votre fournisseur de signature pour obtenir de l’aide." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "L’authentification auprès de votre fournisseur de signature a échoué" diff --git a/packages/lib/translations/it/web.po b/packages/lib/translations/it/web.po index f79ef6cad..238d37e09 100644 --- a/packages/lib/translations/it/web.po +++ b/packages/lib/translations/it/web.po @@ -312,6 +312,12 @@ msgstr "Campo {0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} ti ha invitato a {recipientActionVerb} il documento \"{1}\"." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} per conto di \"{teamName}\" ti ha invitato a {0}<0/>\"{doc msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} per conto di \"{teamName}\" ti ha invitato a {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {Non puoi avere più di # chiave di accesso.} other {Non puoi avere più di # chiavi di accesso.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} ti ha invitato a {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "Account scollegato" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Riconoscimento" @@ -1818,10 +1836,6 @@ msgstr "Si è verificato un errore durante la firma automatica del documento, al msgid "An error occurred while cancelling the documents." msgstr "Si è verificato un errore durante l’annullamento dei documenti." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Si è verificato un errore durante il completamento del documento. Riprova." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Si è verificato un errore durante la creazione del documento dal modello." @@ -2455,6 +2469,10 @@ msgstr "Dimensione del raggio del bordo in unità REM (ad es. 0.5rem)." msgid "Bottom" msgstr "Inferiore" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Colori del brand" @@ -2988,6 +3006,14 @@ msgstr "Elenco di domini email, separati da virgola, da bloccare per la registra msgid "Communication" msgstr "Comunicazione" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Confronta tutti i piani e le caratteristiche in dettaglio" @@ -3174,6 +3200,11 @@ msgstr "Consenso alle transazioni elettroniche" msgid "Contact Information" msgstr "Informazioni di contatto" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Contatta le vendite qui" @@ -3182,6 +3213,10 @@ msgstr "Contatta le vendite qui" msgid "Contact us" msgstr "Contattaci" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Contenuto" @@ -3234,6 +3269,10 @@ msgstr "Continua visualizzando il documento." msgid "Continue to login" msgstr "Continua per accedere" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Determina per quanto tempo i destinatari hanno a disposizione per completare la firma prima che il documento scada. Dopo la scadenza, i destinatari non potranno più firmare il documento." @@ -4335,6 +4374,10 @@ msgstr "Autenticazione accesso documento aggiornata" msgid "Document All" msgstr "Documenta Tutto" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "Documento Approvato" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Documento annullato" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Documento spostato al team" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Documento non più disponibile per la firma" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Preferenze del documento aggiornate" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Documento rifiutato" @@ -4978,6 +5031,10 @@ msgstr "Es. 100" msgid "e.g. Resend (free plans)" msgstr "es. Resend (piani gratuiti)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Inserisci il tuo testo qui" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Impresa" @@ -5562,7 +5621,6 @@ msgstr "Busta aggiornata" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Busta aggiornata" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Estrazione dei dettagli di contatto in corso" msgid "Failed" msgstr "Non riuscito" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Impossibile completare il documento. Riprova." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Creazione del documento non riuscita. Riprova." @@ -6147,6 +6200,10 @@ msgstr "Genera link" msgid "German" msgstr "Tedesco" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Ciao, {userName} <0>({userEmail})" msgid "Hide" msgstr "Nascondi" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Nascondi chiave di licenza" @@ -6789,6 +6850,10 @@ msgstr "Attualmente non è il tuo turno di firmare. Torna presto a controllare p msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "Al momento, non è il tuo turno di firmare. Riceverai un'email con le istruzioni quando sarà il tuo turno di firmare il documento." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italiano" @@ -6907,6 +6972,10 @@ msgstr "Ultimo aggiornamento il" msgid "Last used" msgstr "Ultimo utilizzo" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Gestisci" msgid "Manage {0}'s profile" msgstr "Gestisci il profilo di {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Gestisci un portale di accesso SSO personalizzato per la tua organizzazione." @@ -7531,6 +7601,10 @@ msgstr "Nome richiesto" msgid "Name Settings" msgstr "Impostazioni Nome" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "Necessita di visualizzazione" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Mai" @@ -7944,6 +8019,10 @@ msgstr "Una volta configurato il tuo modello, condividi il link ovunque tu vogli msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Uno dei documenti nel pacchetto corrente ha un ruolo di firma non compatibile con l'esperienza di firma corrente." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Solo gli amministratori possono accedere e visualizzare il documento" @@ -8127,6 +8206,7 @@ msgstr "Ruolo dell'organizzazione" msgid "Organisation Settings" msgstr "Impostazioni dell'organizzazione" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Seleziona almeno un membro da aggiungere al team." msgid "Please select how you'd like to receive your verification code." msgstr "Seleziona come desideri ricevere il tuo codice di verifica." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Si prega di provare un altro dominio." @@ -8859,6 +8944,10 @@ msgstr "Modello pubblico" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "I modelli pubblici sono collegati al tuo profilo pubblico. Ogni modifica ai modelli pubblici apparirà anche nel tuo profilo pubblico." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Azioni rapide" @@ -9187,6 +9276,10 @@ msgstr "Reindirizzamento" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "Header di risposta" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Stai tranquillo, il tuo documento è strettamente confidenziale e non sarà mai condiviso. Solo la tua esperienza di firma sarà evidenziata. Condividi la tua carta di firma personalizzata per mostrare la tua firma!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Accesso limitato" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Cerca per ID reclamo o nome" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Cerca per titolo del documento, team:123 o user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Invia documento" msgid "Send Document" msgstr "Invia documento" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Invia documenti a nome del team utilizzando l'indirizzo email" @@ -10079,6 +10180,10 @@ msgstr "Invia documenti a nome del team utilizzando l'indirizzo email" msgid "Send documents to recipients immediately" msgstr "Invia documenti ai destinatari immediatamente" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Invia busta" @@ -10125,6 +10230,14 @@ msgstr "Mittente" msgid "Sender reported" msgstr "Mittente segnalato" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Invio dell'email di ripristino..." @@ -10145,6 +10258,10 @@ msgstr "Inviato" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sessione revocata" @@ -10250,6 +10367,7 @@ msgstr "Mostra utilizzo con quote" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Firmato" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Firmatario" @@ -10485,6 +10607,10 @@ msgstr "Firma per" msgid "Signing in..." msgstr "Accesso in corso..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "La registrazione è al momento disabilitata o non disponibile per il tuo msgid "Since {0}" msgstr "Dal {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Banner del sito" @@ -10556,6 +10686,10 @@ msgstr "Salta" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "Alcuni firmatari non hanno un campo firma assegnato. Assegna almeno 1 ca #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Alcuni firmatari non hanno un campo firma assegnato. Assegna almeno 1 ca #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Alcuni firmatari non hanno un campo firma assegnato. Assegna almeno 1 ca #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Qualcosa è andato storto" @@ -11137,6 +11269,7 @@ msgstr "URL del team" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Questo documento non può essere recuperato, se vuoi contestare la ragione per i documenti futuri, contatta il supporto." @@ -11920,6 +12057,10 @@ msgstr "Questo documento non può essere duplicato in questo momento. Riprova." msgid "This document could not be saved as a template at this time. Please try again." msgstr "Questo documento non può essere salvato come modello in questo momento. Riprova." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Questo documento è stato annullato dal proprietario e non è più dispo msgid "This document has been cancelled by the owner." msgstr "Questo documento è stato annullato dal proprietario." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Questo documento è stato rifiutato da un destinatario" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Questo documento è stato firmato da tutti i destinatari" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Questo documento ha troppi destinatari. Rimuovi alcuni destinatari oppure contatta l'assistenza se hai bisogno di aggiungerne altri." @@ -11958,6 +12111,10 @@ msgstr "Questo documento è disponibile nel tuo account Documenso. Puoi visualiz msgid "This document is currently a draft and has not been sent" msgstr "Questo documento è attualmente una bozza e non è stato inviato" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Questo documento utilizza l'inserimento campo legacy, consigliamo di utilizzare il nuovo metodo di inserimento campo per risultati più accurati." @@ -12673,6 +12830,18 @@ msgstr "Documenti illimitati, API e altro" msgid "Unlink" msgstr "Scollega" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Rimuovi" @@ -12846,6 +13015,10 @@ msgstr "Aggiorna" msgid "Upgrade <0>{0} to {planName}" msgstr "Aggiorna <0>{0} al {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Aggiorna il tuo piano per caricare più documenti" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "In attesa di altri" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "In attesa che altri completino la firma." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "Non siamo riusciti a impostare il tuo profilo pubblico come pubblico. Pe msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "Non siamo riusciti a impostare l'autenticazione a due fattori per il tuo account. Assicurati di aver inserito correttamente il tuo codice e riprova." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "Non siamo riusciti a inviare questo documento in questo momento. Per favore riprova più tardi." @@ -13830,6 +14001,11 @@ msgstr "Bentornato, siamo fortunati ad averti." msgid "Welcome back! Here's an overview of your account." msgstr "Bentornato! Ecco una panoramica del tuo account." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Benvenuto a {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Ritiro del consenso" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Scrivi una descrizione da mostrare sul tuo profilo pubblico" @@ -14157,10 +14337,6 @@ msgstr "Puoi scegliere di abilitare o disabilitare il profilo per la visualizzaz msgid "You can copy and share these links to recipients so they can action the document." msgstr "Puoi copiare e condividere questi link con i destinatari affinché possano agire sul documento." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Puoi abilitare l'accesso per consentire a tutti i membri dell'organizzazione di accedere a questo team per impostazione predefinita." @@ -14924,6 +15100,10 @@ msgstr "La tua busta è stata distribuita con successo." msgid "Your envelope has been resent successfully." msgstr "La tua busta è stata reinviata con successo." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Il tuo nome" @@ -15057,6 +15237,10 @@ msgstr "La tua autorizzazione alla firma è scaduta prima che la firma potesse e msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Il tuo certificato di firma non è valido, è scaduto o manca di una chiave richiesta. Contatta l'amministratore o il provider di firma per assistenza." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "La tua autenticazione presso il provider di firma non è riuscita" diff --git a/packages/lib/translations/ja/web.po b/packages/lib/translations/ja/web.po index 91f0d33bf..4e451daf9 100644 --- a/packages/lib/translations/ja/web.po +++ b/packages/lib/translations/ja/web.po @@ -312,6 +312,12 @@ msgstr "{0} フィールド" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} からドキュメント「{1}」への{recipientActionVerb}依頼が届いています。" +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} が「{teamName}」を代表して {0}<0/>「{documentName msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} が「{teamName}」を代表して {action} {documentName} を依頼しています" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, other {# 個を超えるパスキーを保持することはできません。}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} から {action} {documentName} の依頼が届いています" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "アカウントのリンクを解除しました" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "確認" @@ -1818,10 +1836,6 @@ msgstr "ドキュメントの自動署名中にエラーが発生しました。 msgid "An error occurred while cancelling the documents." msgstr "文書のキャンセル中にエラーが発生しました。" -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "ドキュメントの完了処理中にエラーが発生しました。もう一度お試しください。" - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "テンプレートから文書を作成する際にエラーが発生しました。" @@ -2455,6 +2469,10 @@ msgstr "ボーダーの角丸サイズ(REM 単位、例: 0.5rem)。" msgid "Bottom" msgstr "下" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "ブランドカラー" @@ -2988,6 +3006,14 @@ msgstr "サインアップをブロックするメールドメインをカンマ msgid "Communication" msgstr "コミュニケーション" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "すべてのプランと機能を詳細に比較" @@ -3174,6 +3200,11 @@ msgstr "電子取引への同意" msgid "Contact Information" msgstr "連絡先情報" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "営業にお問い合わせ" @@ -3182,6 +3213,10 @@ msgstr "営業にお問い合わせ" msgid "Contact us" msgstr "お問い合わせ" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "コンテンツ" @@ -3234,6 +3269,10 @@ msgstr "ドキュメントを表示して続行してください。" msgid "Continue to login" msgstr "ログインを続ける" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "受信者が文書の有効期限切れまでに署名を完了できる期間を設定します。有効期限後は、受信者は文書に署名できなくなります。" @@ -4335,6 +4374,10 @@ msgstr "ドキュメントのアクセス認証が更新されました" msgid "Document All" msgstr "すべての文書" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "文書が承認されました" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "文書は取り消されました" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "ドキュメントがチームに移動されました" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "文書は署名できなくなりました" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "文書設定を更新しました" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "ドキュメントは却下されました" @@ -4978,6 +5031,10 @@ msgstr "例: 100" msgid "e.g. Resend (free plans)" msgstr "例:Resend(無料プラン)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "ここにテキストを入力してください" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5562,7 +5621,6 @@ msgstr "封筒を更新しました" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "封筒を更新しました" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "連絡先情報を抽出しています" msgid "Failed" msgstr "失敗" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "ドキュメントの完了に失敗しました。もう一度お試しください。" - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "ドキュメントの作成に失敗しました。もう一度お試しください。" @@ -6147,6 +6200,10 @@ msgstr "リンクを生成" msgid "German" msgstr "ドイツ語" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "こんにちは、{userName} さん <0>({userEmail})" msgid "Hide" msgstr "非表示" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "ライセンスキーを非表示にする" @@ -6789,6 +6850,10 @@ msgstr "現在はあなたの署名順ではありません。まもなくこの msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "現在はあなたの署名順ではありません。順番が来ると、文書への署名方法を記載したメールが届きます。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "イタリア語" @@ -6907,6 +6972,10 @@ msgstr "最終利用日" msgid "Last used" msgstr "退会" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "管理" msgid "Manage {0}'s profile" msgstr "{0} のプロフィールを管理" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "組織向けのカスタムSSOログインポータルを管理します。" @@ -7531,6 +7601,10 @@ msgstr "名前は必須です" msgid "Name Settings" msgstr "名前の設定" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "閲覧が必要" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "なし" @@ -7944,6 +8019,10 @@ msgstr "テンプレートの設定が完了したら、リンクを好きな場 msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "現在のバンドル内のドキュメントのうち 1 つに、この署名体験と互換性のない署名ロールがあります。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "管理者のみが文書にアクセスして閲覧できます" @@ -8127,6 +8206,7 @@ msgstr "組織ロール" msgid "Organisation Settings" msgstr "組織設定" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "チームに追加するメンバーを少なくとも1人選択して msgid "Please select how you'd like to receive your verification code." msgstr "認証コードの受け取り方法を選択してください。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "別のドメインをお試しください。" @@ -8859,6 +8944,10 @@ msgstr "公開テンプレート" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "公開テンプレートは公開プロフィールに紐づきます。公開テンプレートを変更すると、公開プロフィールにも反映されます。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "クイックアクション" @@ -9187,6 +9276,10 @@ msgstr "リダイレクト中" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "レスポンスヘッダー" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "ドキュメント自体は厳重に機密扱いされ、共有されることはありませんのでご安心ください。強調されるのは署名体験のみです。あなただけの署名カードを共有して、署名をアピールしましょう。" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "アクセス制限" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "クレーム ID または名前で検索" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "文書タイトル、team:123 または user:123 で検索" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "文書を送信" msgid "Send Document" msgstr "ドキュメントを送信" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "このメールアドレスを使用して、チームを代表してドキュメントを送信します" @@ -10079,6 +10180,10 @@ msgstr "このメールアドレスを使用して、チームを代表してド msgid "Send documents to recipients immediately" msgstr "ドキュメントをすぐに受信者へ送信する" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "封筒を送信" @@ -10125,6 +10230,14 @@ msgstr "送信者" msgid "Sender reported" msgstr "送信者を報告しました" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "リセットメールを送信中..." @@ -10145,6 +10258,10 @@ msgstr "送信日時" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "セッションを取り消しました" @@ -10250,6 +10367,7 @@ msgstr "割り当てを含む利用状況を表示する" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "署名済み" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "署名者" @@ -10485,6 +10607,10 @@ msgstr "署名対象" msgid "Signing in..." msgstr "サインインしています..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "サインアップは現在無効になっているか、お使いのメ msgid "Since {0}" msgstr "{0} から" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "サイトバナー" @@ -10556,6 +10686,10 @@ msgstr "スキップ" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "一部の署名者に署名フィールドが割り当てられていま #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "一部の署名者に署名フィールドが割り当てられていま #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "一部の署名者に署名フィールドが割り当てられていま #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "問題が発生しました" @@ -11137,6 +11269,7 @@ msgstr "チーム URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "このドキュメントは復元できません。今後のドキュメントについて理由に異議がある場合は、サポートまでお問い合わせください。" @@ -11920,6 +12057,10 @@ msgstr "この文書は現在複製できません。もう一度お試しくだ msgid "This document could not be saved as a template at this time. Please try again." msgstr "現在、このドキュメントをテンプレートとして保存できません。もう一度お試しください。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "この文書は所有者によりキャンセルされており、他の msgid "This document has been cancelled by the owner." msgstr "この文書は所有者によりキャンセルされました。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "このドキュメントは受信者によって却下されました。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "この文書はすべての受信者によって署名されています" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "このドキュメントの受信者が多すぎます。受信者を減らすか、さらに必要な場合はサポートまでお問い合わせください。" @@ -11958,6 +12111,10 @@ msgstr "このドキュメントは Documenso アカウントで利用できま msgid "This document is currently a draft and has not been sent" msgstr "この文書は現在下書きであり、送信されていません" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "このドキュメントは旧式のフィールド挿入を使用しています。より正確な結果のために、新しいフィールド挿入方法の使用を推奨します。" @@ -12673,6 +12830,18 @@ msgstr "ドキュメント無制限、API など" msgid "Unlink" msgstr "リンク解除" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "ピン留めを解除" @@ -12846,6 +13015,10 @@ msgstr "アップグレード" msgid "Upgrade <0>{0} to {planName}" msgstr "<0>{0} を {planName} にアップグレード" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "プランをアップグレードして、より多くのドキュメントをアップロードしましょう" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "他の人の完了待ち" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "他の署名者による署名完了を待っています。" +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "公開プロフィールを公開状態に変更できませんでした msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "二要素認証を設定できませんでした。コードが正しく入力されているか確認のうえ、再度お試しください。" -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "現在、この文書を送信できませんでした。後でもう一度お試しください。" @@ -13830,6 +14001,11 @@ msgstr "おかえりなさい。あなたにまたお会いできて嬉しいで msgid "Welcome back! Here's an overview of your account." msgstr "お帰りなさい!アカウントの概要をご確認ください。" +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "{organisationName} へようこそ" @@ -13907,6 +14083,10 @@ msgstr "同意の撤回" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "公開プロフィールに表示する説明文を入力してください" @@ -14157,10 +14337,6 @@ msgstr "プロフィールを公開するかどうかを選択できます。" msgid "You can copy and share these links to recipients so they can action the document." msgstr "これらのリンクをコピーして受信者と共有すると、文書に対応してもらうことができます。" -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "このチームに対して、すべての組織メンバーへのデフォルトアクセスを有効にすることができます。" @@ -14924,6 +15100,10 @@ msgstr "封筒を正常に送信しました。" msgid "Your envelope has been resent successfully." msgstr "封筒を正常に再送信しました。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "あなたの名前" @@ -15057,6 +15237,10 @@ msgstr "署名の認可が署名適用前に失効しました。再度認可し msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "署名証明書が無効であるか、有効期限が切れているか、必要な鍵がありません。管理者または署名プロバイダーにお問い合わせください。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "署名プロバイダーでの認証に失敗しました" diff --git a/packages/lib/translations/ko/web.po b/packages/lib/translations/ko/web.po index a15077795..a4c12929d 100644 --- a/packages/lib/translations/ko/web.po +++ b/packages/lib/translations/ko/web.po @@ -312,6 +312,12 @@ msgstr "{0} 필드" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0}에서 \"{1}\" 문서에 대해 귀하께 {recipientActionVerb}하도록 초대했습니다." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName}이(가) \"{0}\"을(를) 대신하여 문서 \"{documentNam msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName}이(가) \"{teamName}\"을(를) 대신하여 {documentName} 문서에 {action}하도록 귀하를 초대했습니다." +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, other {패스키는 #개를 초과하여 가질 수 없습니다.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName}이(가) 귀하께 {action} {documentName} 문서를 요청했습니다." #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "계정 연결 해제됨" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "확인" @@ -1818,10 +1836,6 @@ msgstr "문서를 자동 서명하는 동안 오류가 발생하여 일부 필 msgid "An error occurred while cancelling the documents." msgstr "문서를 취소하는 동안 오류가 발생했습니다." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "문서를 완료하는 중 오류가 발생했습니다. 다시 시도해 주세요." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "템플릿에서 문서를 생성하는 중 오류가 발생했습니다." @@ -2455,6 +2469,10 @@ msgstr "REM 단위의 테두리 반경 크기입니다(예: 0.5rem)." msgid "Bottom" msgstr "아래" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "브랜드 색상" @@ -2988,6 +3006,14 @@ msgstr "가입을 차단할 이메일 도메인을 쉼표로 구분하여 입력 msgid "Communication" msgstr "커뮤니케이션" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "모든 요금제와 기능을 자세히 비교합니다." @@ -3174,6 +3200,11 @@ msgstr "전자 거래에 대한 동의" msgid "Contact Information" msgstr "연락처 정보" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "영업팀에 문의" @@ -3182,6 +3213,10 @@ msgstr "영업팀에 문의" msgid "Contact us" msgstr "문의하기" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "콘텐츠" @@ -3234,6 +3269,10 @@ msgstr "문서를 열람하여 계속 진행하세요." msgid "Continue to login" msgstr "로그인으로 이동" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "수신자가 문서가 만료되기 전에 서명을 완료할 수 있는 기간을 제어합니다. 만료 후에는 수신자가 더 이상 이 문서에 서명할 수 없습니다." @@ -4335,6 +4374,10 @@ msgstr "문서 접근 인증이 업데이트되었습니다." msgid "Document All" msgstr "문서 전체" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "문서 승인됨" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "문서가 취소되었습니다" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "문서가 팀으로 이동되었습니다." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "문서를 더 이상 서명할 수 없습니다" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "문서 환경설정이 업데이트되었습니다" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "문서 거부됨" @@ -4978,6 +5031,10 @@ msgstr "예: 100" msgid "e.g. Resend (free plans)" msgstr "예: Resend(무료 플랜)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "여기에 텍스트를 입력하세요" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5562,7 +5621,6 @@ msgstr "봉투가 업데이트되었습니다" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "봉투가 업데이트되었습니다" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "연락처 정보 추출 중" msgid "Failed" msgstr "실패" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "문서를 완료하지 못했습니다. 다시 시도해 주세요." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "문서 생성에 실패했습니다. 다시 시도해 주세요." @@ -6147,6 +6200,10 @@ msgstr "링크 생성" msgid "German" msgstr "독일어" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "안녕하세요, {userName}님 <0>({userEmail})" msgid "Hide" msgstr "숨기기" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "라이선스 키 숨기기" @@ -6789,6 +6850,10 @@ msgstr "현재는 귀하의 서명 순서가 아닙니다. 곧 이 문서에 서 msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "현재는 귀하의 서명 순서가 아닙니다. 순서가 되면 문서 서명 방법이 안내된 이메일을 받게 됩니다." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "이탈리아어" @@ -6907,6 +6972,10 @@ msgstr "마지막 업데이트 시각" msgid "Last used" msgstr "마지막 사용" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "관리" msgid "Manage {0}'s profile" msgstr "{0}의 프로필 관리" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "조직을 위한 사용자 정의 SSO 로그인 포털을 관리하세요." @@ -7531,6 +7601,10 @@ msgstr "이름은 필수 항목입니다." msgid "Name Settings" msgstr "이름 설정" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "열람 필요" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "없음" @@ -7944,6 +8019,10 @@ msgstr "템플릿 설정을 마친 후 링크를 원하는 곳에 공유하세 msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "현재 번들에 포함된 문서 중 하나에 현재 서명 환경과 호환되지 않는 서명 역할이 있습니다." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "관리자만 문서에 접근하고 열람할 수 있습니다" @@ -8127,6 +8206,7 @@ msgstr "조직 역할" msgid "Organisation Settings" msgstr "조직 설정" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "팀에 추가할 구성원을 최소 한 명 이상 선택하세요." msgid "Please select how you'd like to receive your verification code." msgstr "인증 코드를 받을 방식을 선택하세요." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "다른 도메인을 시도해 주세요." @@ -8859,6 +8944,10 @@ msgstr "공개 템플릿" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "공개 템플릿은 공개 프로필과 연결됩니다. 공개 템플릿을 수정하면 공개 프로필에도 반영됩니다." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "빠른 작업" @@ -9187,6 +9276,10 @@ msgstr "리디렉션 중" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "응답 헤더" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "귀하의 문서는 철저히 비밀로 유지되며 절대 공유되지 않습니다. 강조되는 것은 귀하의 서명 경험뿐입니다. 개인화된 서명 카드를 공유해 서명을 보여 주세요!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "제한된 액세스" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "클레임 ID 또는 이름으로 검색" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "문서 제목, team:123 또는 user:123으로 검색" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "문서 보내기" msgid "Send Document" msgstr "문서 보내기" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "이 이메일 주소를 사용하여 팀을 대신해 문서를 보냅니다." @@ -10079,6 +10180,10 @@ msgstr "이 이메일 주소를 사용하여 팀을 대신해 문서를 보냅 msgid "Send documents to recipients immediately" msgstr "생성된 문서를 즉시 수신자에게 전송" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "봉투 보내기" @@ -10125,6 +10230,14 @@ msgstr "보낸 사람" msgid "Sender reported" msgstr "발신자가 신고되었습니다" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "재설정 이메일 전송 중..." @@ -10145,6 +10258,10 @@ msgstr "발송됨" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "세션이 해지되었습니다." @@ -10250,6 +10367,7 @@ msgstr "할당량과 함께 사용량 표시하기" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "서명됨" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "서명자" @@ -10485,6 +10607,10 @@ msgstr "대리 서명 대상" msgid "Signing in..." msgstr "로그인 중..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "회원가입이 현재 비활성화되어 있거나, 사용자의 이메 msgid "Since {0}" msgstr "{0} 이후" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "사이트 배너" @@ -10556,6 +10686,10 @@ msgstr "건너뛰기" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "일부 서명자에게 서명 필드가 할당되지 않았습니다. #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "일부 서명자에게 서명 필드가 할당되지 않았습니다. #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "일부 서명자에게 서명 필드가 할당되지 않았습니다. #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "문제가 발생했습니다" @@ -11137,6 +11269,7 @@ msgstr "팀 URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "이 문서는 복구할 수 없습니다. 향후 문서에 대한 삭제 사유에 이의를 제기하시려면 고객 지원팀에 문의해 주세요." @@ -11920,6 +12057,10 @@ msgstr "현재 이 문서를 복제할 수 없습니다. 다시 시도해 주세 msgid "This document could not be saved as a template at this time. Please try again." msgstr "현재 이 문서를 템플릿으로 저장할 수 없습니다. 다시 시도해 주세요." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "이 문서는 소유자가 취소했으며, 더 이상 다른 사람이 msgid "This document has been cancelled by the owner." msgstr "이 문서는 소유자가 취소했습니다." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "이 문서는 수신자 중 한 명에 의해 거부되었습니다." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "이 문서는 모든 수신자가 서명했습니다" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "이 문서의 수신자가 너무 많습니다. 일부 수신자를 제거하거나, 더 많은 수신자가 필요하시면 지원팀에 문의해 주세요." @@ -11958,6 +12111,10 @@ msgstr "이 문서는 귀하의 Documenso 계정에서 확인할 수 있습니 msgid "This document is currently a draft and has not been sent" msgstr "이 문서는 현재 초안 상태이며 발송되지 않았습니다" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "이 문서는 기존(레거시) 필드 삽입 방식을 사용하고 있습니다. 더 정확한 결과를 위해 새로운 필드 삽입 방식을 사용하는 것을 권장합니다." @@ -12673,6 +12830,18 @@ msgstr "무제한 문서, API 등" msgid "Unlink" msgstr "연결 해제" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "고정 해제" @@ -12846,6 +13015,10 @@ msgstr "업그레이드" msgid "Upgrade <0>{0} to {planName}" msgstr "<0>{0}을(를) {planName} 요금제로 업그레이드" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "더 많은 문서를 업로드하려면 요금제를 업그레이드하세요." @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "다른 사람을 기다리는 중" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "다른 서명자들이 이 문서에 서명 완료하기를 기다리는 중입니다." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "공개 프로필을 공개로 설정할 수 없습니다. 다시 시도 msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "계정의 2단계 인증을 설정할 수 없습니다. 코드를 올바르게 입력했는지 확인한 후 다시 시도해 주세요." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "현재 이 문서를 제출할 수 없습니다. 나중에 다시 시도해 주세요." @@ -13830,6 +14001,11 @@ msgstr "다시 오신 것을 환영합니다. 함께하게 되어 기쁩니다." msgid "Welcome back! Here's an overview of your account." msgstr "다시 오신 것을 환영합니다! 계정 개요를 확인해 보세요." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "{organisationName}에 오신 것을 환영합니다" @@ -13907,6 +14083,10 @@ msgstr "동의 철회" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "공개 프로필에 표시될 설명을 작성하세요." @@ -14157,10 +14337,6 @@ msgstr "공개 프로필을 공개하거나 비공개로 전환할 수 있습니 msgid "You can copy and share these links to recipients so they can action the document." msgstr "이 링크를 복사해 수신자에게 공유하면 문서에 대해 필요한 작업을 할 수 있습니다." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "조직의 모든 구성원이 기본적으로 이 팀에 접근할 수 있도록 액세스를 활성화할 수 있습니다." @@ -14924,6 +15100,10 @@ msgstr "봉투가 성공적으로 배포되었습니다." msgid "Your envelope has been resent successfully." msgstr "봉투가 성공적으로 다시 전송되었습니다." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "이름" @@ -15057,6 +15237,10 @@ msgstr "전자 서명을 적용하기 전에 서명 권한이 만료되었습니 msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "서명 인증서가 유효하지 않거나, 만료되었거나, 필요한 키가 없습니다. 관리자나 서명 제공자에게 문의해 도움을 받으세요." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "서명 제공자 인증에 실패했습니다." diff --git a/packages/lib/translations/nl/web.po b/packages/lib/translations/nl/web.po index 22acd1cb9..21c56f4d4 100644 --- a/packages/lib/translations/nl/web.po +++ b/packages/lib/translations/nl/web.po @@ -312,6 +312,12 @@ msgstr "{0}-veld" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} heeft je uitgenodigd om het document \"{1}\" te {recipientActionVerb}." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} heeft namens \"{teamName}\" je uitgenodigd om {0}<0/>\"{do msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} heeft namens \"{teamName}\" je uitgenodigd om {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {U kunt niet meer dan # passkey hebben.} other {U kunt niet meer dan # passkeys hebben.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} heeft je uitgenodigd om {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "Account ontkoppeld" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Kennisgeving" @@ -1818,10 +1836,6 @@ msgstr "Er is een fout opgetreden tijdens het automatisch ondertekenen van het d msgid "An error occurred while cancelling the documents." msgstr "Er is een fout opgetreden bij het annuleren van de documenten." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Er is een fout opgetreden bij het voltooien van het document. Probeer het opnieuw." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Er is een fout opgetreden bij het aanmaken van een document op basis van de sjabloon." @@ -2455,6 +2469,10 @@ msgstr "Grootte van afgeronde hoeken in REM-eenheden (bijv. 0.5rem)." msgid "Bottom" msgstr "Onder" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Merkkleuren" @@ -2988,6 +3006,14 @@ msgstr "Komma-gescheiden lijst met e‑maildomeinen die voor registratie moeten msgid "Communication" msgstr "Communicatie" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Vergelijk alle abonnementen en functies in detail" @@ -3174,6 +3200,11 @@ msgstr "Toestemming voor elektronische transacties" msgid "Contact Information" msgstr "Contactgegevens" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Neem hier contact op met sales" @@ -3182,6 +3213,10 @@ msgstr "Neem hier contact op met sales" msgid "Contact us" msgstr "Neem contact met ons op" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Inhoud" @@ -3234,6 +3269,10 @@ msgstr "Ga verder door het document te bekijken." msgid "Continue to login" msgstr "Doorgaan naar inloggen" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Bepaalt hoe lang ontvangers de tijd hebben om te ondertekenen voordat het document verloopt. Na de vervaldatum kunnen ontvangers het document niet meer ondertekenen." @@ -4335,6 +4374,10 @@ msgstr "Documenttoegangsautorisatie bijgewerkt" msgid "Document All" msgstr "Document alles" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "Document goedgekeurd" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Document geannuleerd" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Document naar team verplaatst" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Document niet langer beschikbaar om te ondertekenen" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Documentvoorkeuren bijgewerkt" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Document geweigerd" @@ -4978,6 +5031,10 @@ msgstr "Bijv. 100" msgid "e.g. Resend (free plans)" msgstr "bijv. Resend (gratis abonnementen)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Voer hier je tekst in" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5562,7 +5621,6 @@ msgstr "Envelope bijgewerkt" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Envelope bijgewerkt" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Contactgegevens extraheren" msgid "Failed" msgstr "Mislukt" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Het is niet gelukt om het document te voltooien. Probeer het opnieuw." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Het document kon niet worden aangemaakt. Probeer het opnieuw." @@ -6147,6 +6200,10 @@ msgstr "Links genereren" msgid "German" msgstr "Duits" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Hoi, {userName} <0>({userEmail})" msgid "Hide" msgstr "Verbergen" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Licentiesleutel verbergen" @@ -6789,6 +6850,10 @@ msgstr "Het is momenteel niet jouw beurt om te ondertekenen. Kom binnenkort teru msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "Het is momenteel niet jouw beurt om te ondertekenen. Je ontvangt een e‑mail met instructies zodra jij aan de beurt bent om het document te ondertekenen." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Italiaans" @@ -6907,6 +6972,10 @@ msgstr "Laatst bijgewerkt op" msgid "Last used" msgstr "Laatst gebruikt" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Beheren" msgid "Manage {0}'s profile" msgstr "Profiel van {0} beheren" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Beheer een aangepast SSO-inlogportaal voor uw organisatie." @@ -7531,6 +7601,10 @@ msgstr "Naam is verplicht" msgid "Name Settings" msgstr "Naam-instellingen" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "Moet bekijken" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Nooit" @@ -7944,6 +8019,10 @@ msgstr "Zodra je sjabloon is ingesteld, kun je de link overal delen. Degene die msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Een van de documenten in de huidige bundel heeft een ondertekeningsrol die niet compatibel is met de huidige ondertekeningservaring." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Alleen beheerders kunnen toegang krijgen tot en het document bekijken" @@ -8127,6 +8206,7 @@ msgstr "Organisatierol" msgid "Organisation Settings" msgstr "Organisatie-instellingen" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Selecteer minstens één lid om aan het team toe te voegen." msgid "Please select how you'd like to receive your verification code." msgstr "Selecteer hoe u uw verificatiecode wilt ontvangen." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Probeer een ander domein." @@ -8859,6 +8944,10 @@ msgstr "Publieke sjabloon" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Openbare sjablonen zijn gekoppeld aan je openbare profiel. Alle wijzigingen aan openbare sjablonen worden ook zichtbaar in je openbare profiel." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Snelle acties" @@ -9187,6 +9276,10 @@ msgstr "Doorsturen" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "Responsheaders" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Wees gerust, je document is strikt vertrouwelijk en wordt nooit gedeeld. Alleen je ondertekeningservaring wordt uitgelicht. Deel je gepersonaliseerde ondertekeningskaart om je handtekening te laten zien!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Beperkte toegang" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Zoeken op claim-ID of naam" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Zoeken op documenttitel, team:123 of user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Document verzenden" msgid "Send Document" msgstr "Document verzenden" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Documenten versturen namens het team met dit e-mailadres" @@ -10079,6 +10180,10 @@ msgstr "Documenten versturen namens het team met dit e-mailadres" msgid "Send documents to recipients immediately" msgstr "Documenten direct naar ontvangers verzenden" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Envelope verzenden" @@ -10125,6 +10230,14 @@ msgstr "Afzender" msgid "Sender reported" msgstr "Afzender gerapporteerd" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Resetmail wordt verzonden..." @@ -10145,6 +10258,10 @@ msgstr "Verzonden" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sessie ingetrokken" @@ -10250,6 +10367,7 @@ msgstr "Gebruik met quota weergeven" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Ondertekend" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Ondertekenaar" @@ -10485,6 +10607,10 @@ msgstr "Ondertekenen voor" msgid "Signing in..." msgstr "Bezig met inloggen..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "Registratie is momenteel uitgeschakeld of niet beschikbaar voor jouw e msgid "Since {0}" msgstr "Sinds {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Sitebanner" @@ -10556,6 +10686,10 @@ msgstr "Overslaan" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "Sommige ondertekenaars hebben geen handtekeningveld toegewezen gekregen. #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Sommige ondertekenaars hebben geen handtekeningveld toegewezen gekregen. #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Sommige ondertekenaars hebben geen handtekeningveld toegewezen gekregen. #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Er is iets misgegaan" @@ -11137,6 +11269,7 @@ msgstr "Team‑URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Dit document kan niet worden teruggezet. Als je de reden voor toekomstige documenten wilt betwisten, neem dan contact op met de ondersteuning." @@ -11920,6 +12057,10 @@ msgstr "Dit document kan nu niet worden gedupliceerd. Probeer het opnieuw." msgid "This document could not be saved as a template at this time. Please try again." msgstr "Dit document kan op dit moment niet als sjabloon worden opgeslagen. Probeer het opnieuw." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Dit document is door de eigenaar geannuleerd en is niet langer beschikba msgid "This document has been cancelled by the owner." msgstr "Dit document is door de eigenaar geannuleerd." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Dit document is geweigerd door een ontvanger" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Dit document is door alle ontvangers ondertekend" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Dit document heeft te veel ontvangers. Verwijder enkele ontvangers of neem contact op met support als u er meer nodig heeft." @@ -11958,6 +12111,10 @@ msgstr "Dit document is beschikbaar in je Documenso-account. Je kunt daar meer d msgid "This document is currently a draft and has not been sent" msgstr "Dit document is momenteel een concept en is nog niet verzonden" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Dit document gebruikt verouderde veldinvoeging. We raden aan de nieuwe methode voor veldinvoeging te gebruiken voor nauwkeurigere resultaten." @@ -12673,6 +12830,18 @@ msgstr "Onbeperkte documenten, API en meer" msgid "Unlink" msgstr "Ontkoppelen" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Losmaken" @@ -12846,6 +13015,10 @@ msgstr "Upgraden" msgid "Upgrade <0>{0} to {planName}" msgstr "Upgrade <0>{0} naar {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Upgrade je abonnement om meer documenten te uploaden" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "Wachten op anderen" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Wachten tot anderen het ondertekenen hebben voltooid." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "We konden je openbare profiel nu niet op openbaar zetten. Probeer het op msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "We konden twee‑factor‑authenticatie voor je account niet instellen. Controleer of je de code correct hebt ingevoerd en probeer het opnieuw." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "We konden dit document nu niet indienen. Probeer het later opnieuw." @@ -13830,6 +14001,11 @@ msgstr "Welkom terug, we boffen met je." msgid "Welcome back! Here's an overview of your account." msgstr "Welkom terug! Hier is een overzicht van je account." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Welkom bij {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Toestemming intrekken" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Schrijf een beschrijving die op je openbare profiel wordt weergegeven" @@ -14157,10 +14337,6 @@ msgstr "Je kunt ervoor kiezen het profiel in of uit te schakelen voor openbare w msgid "You can copy and share these links to recipients so they can action the document." msgstr "Je kunt deze links kopiëren en met ontvangers delen zodat zij actie op het document kunnen ondernemen." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Je kunt de toegang inschakelen zodat alle organisatieleden standaard toegang hebben tot dit team." @@ -14924,6 +15100,10 @@ msgstr "Uw envelop is succesvol verzonden." msgid "Your envelope has been resent successfully." msgstr "Uw envelop is succesvol opnieuw verzonden." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Uw naam" @@ -15057,6 +15237,10 @@ msgstr "Uw ondertekeningsautorisatie is verlopen voordat de handtekening kon wor msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Uw ondertekeningscertificaat is ongeldig, verlopen of mist een vereiste sleutel. Neem contact op met uw beheerder of ondertekeningsprovider voor hulp." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "Uw verificatie bij de ondertekeningsprovider is mislukt" diff --git a/packages/lib/translations/pl/web.po b/packages/lib/translations/pl/web.po index 4aa5c117d..f9eeddd0d 100644 --- a/packages/lib/translations/pl/web.po +++ b/packages/lib/translations/pl/web.po @@ -312,6 +312,12 @@ msgstr "{0}" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "Sprawdź i {recipientActionVerb} dokument „{1}” utworzony przez zespół {0}." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "Sprawdź i {0} dokument<0/>„{documentName}” utworzony przez użytkow msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "Sprawdź i {action} dokument „{documentName}” utworzony przez użytkownika {inviterName} z zespołu „{teamName}”" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {Nie możesz mieć więcej niż # klucz dostępu.} few {Nie możesz mieć więcej niż # klucze dostępu.} many {Nie możesz mieć więcej niż # kluczy dostępu.} other {Nie możesz mieć więcej niż # kluczy dostępu.}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "Sprawdź i {action} dokument „{documentName}” utworzony przez zespół {teamName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "Ustawienia konta" msgid "Account unlinked" msgstr "Konto zostało rozłączone" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Potwierdzenie" @@ -1818,10 +1836,6 @@ msgstr "Wystąpił błąd podczas automatycznego podpisywania dokumentu. Niektó msgid "An error occurred while cancelling the documents." msgstr "Wystąpił błąd podczas anulowania dokumentów." -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Wystąpił błąd podczas próby zakończenia dokumentu. Spróbuj ponownie." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Wystąpił błąd podczas tworzenia dokumentu z szablonu." @@ -2455,6 +2469,10 @@ msgstr "Rozmiar zaokrąglenia obramowania w jednostkach REM (np. 0.5rem)." msgid "Bottom" msgstr "Dół" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "Kolory marki" @@ -2988,6 +3006,14 @@ msgstr "Lista zablokowanych domen do rejestracji oddzielona przecinkami." msgid "Communication" msgstr "Komunikacja" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Porównaj wszystkie plany i funkcje" @@ -3174,6 +3200,11 @@ msgstr "Zgoda na umowy elektroniczne" msgid "Contact Information" msgstr "Informacje kontaktowe" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Skontaktuj się z działem sprzedaży" @@ -3182,6 +3213,10 @@ msgstr "Skontaktuj się z działem sprzedaży" msgid "Contact us" msgstr "Skontaktuj się z nami" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Zawartość" @@ -3234,6 +3269,10 @@ msgstr "Wyświetl dokument." msgid "Continue to login" msgstr "Przejdź do logowania" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "Określa, ile czasu mają odbiorcy na podpisanie dokumentu przed jego wygaśnięciem. Po tym czasie odbiorcy nie będą mogli już podpisać dokumentu." @@ -4335,6 +4374,10 @@ msgstr "Zaktualizowano metodę uwierzytelniania do dokumentu" msgid "Document All" msgstr "Wszystkie dokumenty" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "Dokument został już podpisany" @@ -4345,6 +4388,7 @@ msgstr "Dokument został zatwierdzony" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "Anulowano dokument" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Przeniesiono dokument do zespołu" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Dokument nie jest już dostępny do podpisania" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "Ustawienia dokumentu zostały zaktualizowane" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Odrzucono dokument" @@ -4978,6 +5031,10 @@ msgstr "Np. 100" msgid "e.g. Resend (free plans)" msgstr "np. Resend (plan darmowy)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "Wpisz tekst" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Enterprise" @@ -5562,7 +5621,6 @@ msgstr "Koperta została zaktualizowana" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "Koperta została zaktualizowana" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "Wyodrębnianie danych kontaktowych" msgid "Failed" msgstr "Niepowodzenie" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Nie udało się zakończyć dokumentu. Spróbuj ponownie." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "Nie udało się utworzyć dokumentu. Spróbuj ponownie." @@ -6147,6 +6200,10 @@ msgstr "Wygeneruj linki" msgid "German" msgstr "Niemiecki" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "Cześć, {userName} <0>({userEmail})" msgid "Hide" msgstr "Ukryj" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "Ukryj klucz licencyjny" @@ -6789,6 +6850,10 @@ msgstr "Obecnie nie jest Twoja kolej na podpisanie dokumentu. Sprawdź dokument msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "To nie jest Twoja kolej na podpisanie dokumentu. Gdy nadejdzie Twoja kolej, otrzymasz wiadomość z instrukcjami." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "Włoski" @@ -6907,6 +6972,10 @@ msgstr "Zaktualizowano" msgid "Last used" msgstr "Użyto" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "Zarządzaj" msgid "Manage {0}'s profile" msgstr "Zarządzaj profilem {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Zarządzaj niestandardowym logowaniem SSO dla swojej organizacji." @@ -7531,6 +7601,10 @@ msgstr "Nazwa jest wymagana" msgid "Name Settings" msgstr "Ustawienia nazwy" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "Nawiguj" @@ -7558,6 +7632,7 @@ msgstr "Musi wyświetlić" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Nigdy" @@ -7944,6 +8019,10 @@ msgstr "Udostępnij link w dowolnym miejscu. Osoba, która otworzy link, będzie msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Jeden z dokumentów ma niezgodną rolę w procesie podpisywania." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Tylko administratorzy mogą uzyskać dostęp do dokumentu i go wyświetlić" @@ -8127,6 +8206,7 @@ msgstr "Rola w organizacji" msgid "Organisation Settings" msgstr "Ustawienia organizacji" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "Wybierz co najmniej jednego użytkownika, aby dodać go do zespołu." msgid "Please select how you'd like to receive your verification code." msgstr "Wybierz, w jaki sposób chcesz otrzymać swój kod weryfikacyjny." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Wybierz inną domenę." @@ -8859,6 +8944,10 @@ msgstr "Szablon publiczny" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Szablony publiczne są powiązane z Twoim profilem publicznym. Wszelkie zmiany szablonów publicznych pojawią się również w Twoim profilu publicznym." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Szybkie akcje" @@ -9187,6 +9276,10 @@ msgstr "Przekierowywanie" msgid "Redirecting to {0}..." msgstr "Przekierowywanie do {0}..." +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "Nagłówki odpowiedzi" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Zapewniamy, że Twój dokument jest poufny i nigdy nie zostanie udostępniony. Udostępnione zostaną tylko Twoje wrażenia związane z podpisywaniem dokumentu. Udostępnij spersonalizowaną kartę ze swoim podpisem!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Dostęp ograniczony" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "Szukaj identyfikatora lub nazwy" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "Szukaj tytułu dokumentu, zespołu lub użytkownika" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "Wyślij dokument" msgid "Send Document" msgstr "Wyślij dokument" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Wysyłanie dokumentów za pomocą Twojego adresu e-mail" @@ -10079,6 +10180,10 @@ msgstr "Wysyłanie dokumentów za pomocą Twojego adresu e-mail" msgid "Send documents to recipients immediately" msgstr "Wyślij dokumenty do odbiorców natychmiast" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "Wyślij kopertę" @@ -10125,6 +10230,14 @@ msgstr "Nadawca" msgid "Sender reported" msgstr "Nadawca został zgłoszony" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Wysyłanie wiadomości..." @@ -10145,6 +10258,10 @@ msgstr "Wysłano" msgid "Sent this period" msgstr "Wysłano w tym okresie" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sesja została unieważniona" @@ -10250,6 +10367,7 @@ msgstr "Pokaż limity użycia" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Podpisany" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Podpisujący" @@ -10485,6 +10607,10 @@ msgstr "Podpisywanie w imieniu" msgid "Signing in..." msgstr "Logowanie..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "Rejestracja dla tej domeny jest wyłączona lub niedostępna." msgid "Since {0}" msgstr "Od {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Baner strony internetowej" @@ -10556,6 +10686,10 @@ msgstr "Pomiń" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "Niektóre pola są umieszczone jedno nad drugim. Może to utrudnić podpisywanie lub spowodować, że pola nie będą działać zgodnie z oczekiwaniami." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "Niektóre wyszukiwania nie powiodły się. Wyniki mogą być niekompletne." @@ -10577,7 +10711,6 @@ msgstr "Niektórym podpisującym nie przypisano pola podpisu. Przypisz co najmni #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "Niektórym podpisującym nie przypisano pola podpisu. Przypisz co najmni #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "Niektórym podpisującym nie przypisano pola podpisu. Przypisz co najmni #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Coś poszło nie tak" @@ -11137,6 +11269,7 @@ msgstr "Adres URL zespołu" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "Szablon bezpośredniego linku nie może zostać użyty, ponieważ co naj msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "Szablon bezpośredniego linku nie może zostać użyty, ponieważ co najmniej jeden podpisujący nie ma przypisanego pola podpisu. Skontaktuj się z nadawcą, aby zaktualizował szablon." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Dokument nie może być odzyskany. Jeśli chcesz zakwestionować decyzję, skontaktuj się z pomocą techniczną." @@ -11920,6 +12057,10 @@ msgstr "Nie można zduplikować dokumentu. Spróbuj ponownie." msgid "This document could not be saved as a template at this time. Please try again." msgstr "Nie można zapisać dokumentu jako szablonu. Spróbuj ponownie." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "Dokument został anulowany przez właściciela i nie jest już dostępny msgid "This document has been cancelled by the owner." msgstr "Dokument został anulowany przez właściciela." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Dokument został odrzucony przez odbiorcę" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Dokument został podpisany przez wszystkich odbiorców" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "Dokument ma zbyt wielu odbiorców. Usuń niektórych odbiorców lub skontaktuj się z pomocą techniczną, jeśli potrzebujesz więcej." @@ -11958,6 +12111,10 @@ msgstr "Na Twoim koncie w Documenso dostępny jest dokument. Możesz zobaczyć w msgid "This document is currently a draft and has not been sent" msgstr "Dokument jest szkicem i nie został wysłany" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Dokument używa starszej metody wstawiania pól. Zalecamy użycie nowej metody." @@ -12673,6 +12830,18 @@ msgstr "Nieograniczona liczba dokumentów, API i więcej" msgid "Unlink" msgstr "Rozłącz" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Odepnij" @@ -12846,6 +13015,10 @@ msgstr "Ulepsz" msgid "Upgrade <0>{0} to {planName}" msgstr "Ulepsz organizację <0>{0} do planu {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Ulepsz plan, aby przesłać więcej dokumentów" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "Oczekiwanie na innych" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Oczekiwanie na zakończenie podpisywania przez innych" +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "Nie mogliśmy zmienić Twojego profilu publicznego na prywatny. Spróbuj msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "Nie mogliśmy skonfigurować weryfikacji dwuetapowej konta. Sprawdź poprawność kodu, a następnie spróbuj ponownie." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "Nie mogliśmy przesłać dokumentu. Spróbuj ponownie później." @@ -13830,6 +14001,11 @@ msgstr "Witaj ponownie. Mamy szczęście, że Cię mamy." msgid "Welcome back! Here's an overview of your account." msgstr "Witaj z powrotem! Oto podsumowanie Twojego konta." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Witaj w organizacji {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "Wycofanie zgody" msgid "Within limit" msgstr "W ramach limitu" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Wpisz opis, który będzie wyświetlany w profilu publicznym" @@ -14157,10 +14337,6 @@ msgstr "Możesz zarządzać widocznością profilu." msgid "You can copy and share these links to recipients so they can action the document." msgstr "Możesz skopiować i udostępnić te linki odbiorcom, aby mogli wypełnić dokument." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Możesz włączyć domyślny dostęp, aby wszyscy użytkownicy organizacji domyślnie uzyskali dostęp do tego zespołu." @@ -14924,6 +15100,10 @@ msgstr "Koperta została wysłana." msgid "Your envelope has been resent successfully." msgstr "Koperta została ponownie wysłana." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Twoja nazwa" @@ -15057,6 +15237,10 @@ msgstr "Autoryzacja podpisu wygasła przed jego złożeniem. Spróbuj ponownie." msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "Certyfikat podpisu jest nieważny, wygasł lub brakuje w nim wymaganego klucza. Skontaktuj się z administratorem lub dostawcą podpisu." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "Twoje uwierzytelnienie u dostawcy podpisu nie powiodło się" diff --git a/packages/lib/translations/pt-BR/web.po b/packages/lib/translations/pt-BR/web.po index 9c51f1854..2f8321151 100644 --- a/packages/lib/translations/pt-BR/web.po +++ b/packages/lib/translations/pt-BR/web.po @@ -307,6 +307,12 @@ msgstr "" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} convidou você para {recipientActionVerb} o documento \"{1}\"." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -429,6 +435,10 @@ msgstr "{inviterName} em nome de \"{teamName}\" convidou você para {0}<0/>\"{do msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} em nome de \"{teamName}\" convidou você para {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, one {Você não pode ter mais de # passkey.} other {Você não pode ter mais de # passkeys.}}" @@ -509,7 +519,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} convidou você para {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1216,6 +1230,10 @@ msgstr "" msgid "Account unlinked" msgstr "Conta desvinculada" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "Reconhecimento" @@ -1813,10 +1831,6 @@ msgstr "Ocorreu um erro ao assinar automaticamente o documento, alguns campos po msgid "An error occurred while cancelling the documents." msgstr "" -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "Ocorreu um erro ao concluir o documento. Por favor, tente novamente." - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "Ocorreu um erro ao criar o documento a partir do modelo." @@ -2450,6 +2464,10 @@ msgstr "" msgid "Bottom" msgstr "Inferior" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "" @@ -2983,6 +3001,14 @@ msgstr "" msgid "Communication" msgstr "Comunicação" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "Compare todos os planos e recursos em detalhes" @@ -3169,6 +3195,11 @@ msgstr "Consentimento para Transações Eletrônicas" msgid "Contact Information" msgstr "Informações de Contato" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "Contate vendas aqui" @@ -3177,6 +3208,10 @@ msgstr "Contate vendas aqui" msgid "Contact us" msgstr "Contate-nos" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "Conteúdo" @@ -3229,6 +3264,10 @@ msgstr "Continue visualizando o documento." msgid "Continue to login" msgstr "Continuar para o login" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "" @@ -4330,6 +4369,10 @@ msgstr "Autenticação de acesso ao documento atualizada" msgid "Document All" msgstr "Documento Todos" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4340,6 +4383,7 @@ msgstr "Documento Aprovado" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "" @@ -4514,10 +4558,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "Documento movido para a equipe" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "Documento não está mais disponível para assinar" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4545,6 +4597,7 @@ msgstr "Preferências de documento atualizadas" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "Documento rejeitado" @@ -4973,6 +5026,10 @@ msgstr "Ex: 100" msgid "e.g. Resend (free plans)" msgstr "" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5491,6 +5548,8 @@ msgid "Enter your text here" msgstr "Digite seu texto aqui" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "Empresarial" @@ -5557,7 +5616,6 @@ msgstr "Envelope atualizado" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5568,7 +5626,6 @@ msgstr "Envelope atualizado" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5738,10 +5795,6 @@ msgstr "Extraindo detalhes de contato" msgid "Failed" msgstr "Falhou" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "Falha ao concluir o documento. Tente novamente." - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "" @@ -6142,6 +6195,10 @@ msgstr "Gerar Links" msgid "German" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6374,6 +6431,10 @@ msgstr "Olá, {userName} <0>({userEmail})" msgid "Hide" msgstr "Ocultar" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "" @@ -6784,6 +6845,10 @@ msgstr "No momento, não é sua vez de assinar. Verifique novamente em breve, po msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "No momento, não é sua vez de assinar. Você receberá um e-mail com instruções assim que for sua vez de assinar o documento." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "" @@ -6902,6 +6967,10 @@ msgstr "Última atualização em" msgid "Last used" msgstr "Último uso" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7100,6 +7169,7 @@ msgstr "Gerenciar" msgid "Manage {0}'s profile" msgstr "Gerenciar perfil de {0}" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "Gerencie um portal de login SSO personalizado para sua organização." @@ -7526,6 +7596,10 @@ msgstr "O nome é obrigatório" msgid "Name Settings" msgstr "Configurações de Nome" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7553,6 +7627,7 @@ msgstr "Precisa visualizar" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "Nunca" @@ -7939,6 +8014,10 @@ msgstr "Assim que seu modelo estiver configurado, compartilhe o link onde quiser msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "Um dos documentos no pacote atual tem uma função de assinatura que não é compatível com a experiência de assinatura atual." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "Apenas administradores podem acessar e visualizar o documento" @@ -8122,6 +8201,7 @@ msgstr "Função na Organização" msgid "Organisation Settings" msgstr "Configurações da Organização" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8668,6 +8748,11 @@ msgstr "" msgid "Please select how you'd like to receive your verification code." msgstr "Por favor, selecione como você gostaria de receber seu código de verificação." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "Por favor, tente um domínio diferente." @@ -8854,6 +8939,10 @@ msgstr "Modelo Público" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "Modelos públicos estão conectados ao seu perfil público. Quaisquer modificações em modelos públicos também aparecerão no seu perfil público." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "Ações Rápidas" @@ -9182,6 +9271,10 @@ msgstr "Redirecionando" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9550,6 +9643,10 @@ msgstr "Cabeçalhos de Resposta" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "Fique tranquilo, seu documento é estritamente confidencial e nunca será compartilhado. Apenas sua experiência de assinatura será destacada. Compartilhe seu cartão de assinatura personalizado para mostrar sua assinatura!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "Acesso Restrito" @@ -9711,7 +9808,7 @@ msgid "Search by claim ID or name" msgstr "Pesquisar por ID ou nome da reivindicação" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" +msgid "Search by document title, recipient:123, team:123 or user:123" msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx @@ -10066,6 +10163,10 @@ msgstr "Enviar documento" msgid "Send Document" msgstr "Enviar Documento" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "Enviar documentos em nome da equipe usando o endereço de e-mail" @@ -10074,6 +10175,10 @@ msgstr "Enviar documentos em nome da equipe usando o endereço de e-mail" msgid "Send documents to recipients immediately" msgstr "Enviar documentos para destinatários imediatamente" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "" @@ -10120,6 +10225,14 @@ msgstr "Remetente" msgid "Sender reported" msgstr "" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "Enviando E-mail de Redefinição..." @@ -10140,6 +10253,10 @@ msgstr "Enviado" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "Sessão revogada" @@ -10245,6 +10362,7 @@ msgstr "" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10416,6 +10534,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "Assinado" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "Signatário" @@ -10480,6 +10602,10 @@ msgstr "Assinando para" msgid "Signing in..." msgstr "Entrando..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10532,6 +10658,10 @@ msgstr "" msgid "Since {0}" msgstr "Desde {0}" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "Banner do Site" @@ -10551,6 +10681,10 @@ msgstr "Pular" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10572,7 +10706,6 @@ msgstr "Alguns signatários não receberam um campo de assinatura. Por favor, at #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10582,8 +10715,6 @@ msgstr "Alguns signatários não receberam um campo de assinatura. Por favor, at #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10606,6 +10737,7 @@ msgstr "Alguns signatários não receberam um campo de assinatura. Por favor, at #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "Algo deu errado" @@ -11132,6 +11264,7 @@ msgstr "URL da Equipe" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11887,6 +12020,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "Este documento não pode ser recuperado, se você quiser contestar o motivo para documentos futuros, entre em contato com o suporte." @@ -11915,6 +12052,10 @@ msgstr "Este documento não pôde ser duplicado neste momento. Por favor, tente msgid "This document could not be saved as a template at this time. Please try again." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11933,14 +12074,26 @@ msgstr "Este documento foi cancelado pelo proprietário e não está mais dispon msgid "This document has been cancelled by the owner." msgstr "Este documento foi cancelado pelo proprietário." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "Este documento foi rejeitado por um destinatário" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "Este documento foi assinado por todos os destinatários" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "" @@ -11953,6 +12106,10 @@ msgstr "Este documento está disponível em sua conta Documenso. Você pode ver msgid "This document is currently a draft and has not been sent" msgstr "Este documento é atualmente um rascunho e não foi enviado" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "Este documento está usando inserção de campo legada, recomendamos usar o novo método de inserção de campo para resultados mais precisos." @@ -12668,6 +12825,18 @@ msgstr "Documentos ilimitados, API e mais" msgid "Unlink" msgstr "Desvincular" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "Desafixar" @@ -12841,6 +13010,10 @@ msgstr "Fazer upgrade" msgid "Upgrade <0>{0} to {planName}" msgstr "Fazer upgrade de <0>{0} para {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "Faça upgrade do seu plano para enviar mais documentos" @@ -13327,8 +13500,8 @@ msgid "Waiting for others" msgstr "Aguardando outros" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "Aguardando outros completarem a assinatura." +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13657,9 +13830,7 @@ msgstr "Não conseguimos definir seu perfil público como público. Por favor, t msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "Não conseguimos configurar a autenticação de dois fatores para sua conta. Por favor, certifique-se de que inseriu seu código corretamente e tente novamente." -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "Não conseguimos enviar este documento neste momento. Por favor, tente novamente mais tarde." @@ -13825,6 +13996,11 @@ msgstr "Bem-vindo de volta, temos sorte em ter você." msgid "Welcome back! Here's an overview of your account." msgstr "Bem-vindo de volta! Aqui está uma visão geral da sua conta." +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "Bem-vindo à {organisationName}" @@ -13902,6 +14078,10 @@ msgstr "Retirada de Consentimento" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "Escreva uma descrição para exibir em seu perfil público" @@ -14152,10 +14332,6 @@ msgstr "Você pode optar por ativar ou desativar o perfil para visualização p msgid "You can copy and share these links to recipients so they can action the document." msgstr "Você pode copiar e compartilhar esses links com os destinatários para que eles possam agir sobre o documento." -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "Você pode ativar o acesso para permitir que todos os membros da organização acessem esta equipe por padrão." @@ -14919,6 +15095,10 @@ msgstr "Seu envelope foi distribuído com sucesso." msgid "Your envelope has been resent successfully." msgstr "Seu envelope foi reenviado com sucesso." +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "Seu Nome" @@ -15052,6 +15232,10 @@ msgstr "" msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "" diff --git a/packages/lib/translations/zh/web.po b/packages/lib/translations/zh/web.po index 806045feb..d0f89f4ca 100644 --- a/packages/lib/translations/zh/web.po +++ b/packages/lib/translations/zh/web.po @@ -312,6 +312,12 @@ msgstr "{0} 字段" msgid "{0} has invited you to {recipientActionVerb} the document \"{1}\"." msgstr "{0} 已邀请您 {recipientActionVerb} 文档“{1}”。" +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "{0} has invited you to sign this document." +msgstr "" + #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts msgid "{0} invited you to {recipientActionVerb} a document" @@ -434,6 +440,10 @@ msgstr "{inviterName} 代表“{teamName}”已邀请您 {0}<0/>“{documentName msgid "{inviterName} on behalf of \"{teamName}\" has invited you to {action} {documentName}" msgstr "{inviterName} 代表“{teamName}”已邀请您 {action} {documentName}" +#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx +msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" +msgstr "" + #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" msgstr "{MAXIMUM_PASSKEYS, plural, other {您不能拥有超过 # 个通行密钥。}}" @@ -514,7 +524,11 @@ msgid "{teamName} has invited you to {action} {documentName}" msgstr "{teamName} 已邀请您 {action} {documentName}" #: apps/remix/app/components/general/app-command-menu.tsx -msgid "{totalVisibleCount} items" +msgid "{totalVisibleCount, plural, one {# item} other {# items}}" +msgstr "" + +#: apps/remix/app/components/general/app-command-menu.tsx +msgid "{totalVisibleCount, plural, one {# result} other {# results}}" msgstr "" #: packages/lib/utils/document-audit-logs.ts @@ -1221,6 +1235,10 @@ msgstr "" msgid "Account unlinked" msgstr "账户已取消关联" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Accounts are automatically added to your organisation on sign-in" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" msgstr "确认" @@ -1818,10 +1836,6 @@ msgstr "自动签署文档时发生错误,部分字段可能未签署。请检 msgid "An error occurred while cancelling the documents." msgstr "取消文档时发生错误。" -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx -msgid "An error occurred while completing the document. Please try again." -msgstr "完成文档时发生错误。请重试。" - #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." msgstr "从模板创建文档时发生错误。" @@ -2455,6 +2469,10 @@ msgstr "边框圆角大小,以 REM 为单位(例如 0.5rem)。" msgid "Bottom" msgstr "底部对齐" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Brand accent" +msgstr "" + #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" msgstr "品牌颜色" @@ -2988,6 +3006,14 @@ msgstr "用逗号分隔的邮箱域名列表,这些域名将被禁止注册。 msgid "Communication" msgstr "通信" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Company details and website in email footers" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" msgstr "详细比较所有套餐和功能" @@ -3174,6 +3200,11 @@ msgstr "同意以电子方式进行交易" msgid "Contact Information" msgstr "联系信息" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Contact Sales" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" msgstr "在此联系销售" @@ -3182,6 +3213,10 @@ msgstr "在此联系销售" msgid "Contact us" msgstr "联系我们" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Contact your organisation owner to upgrade plans." +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" msgstr "内容" @@ -3234,6 +3269,10 @@ msgstr "继续查看文档。" msgid "Continue to login" msgstr "继续登录" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Continue with SSO" +msgstr "" + #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." msgstr "控制收件人在文档过期前完成签署的时间长度。过期后,收件人将无法再签署该文档。" @@ -4335,6 +4374,10 @@ msgstr "文档访问认证已更新" msgid "Document All" msgstr "文档全部" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document already completed" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" msgstr "" @@ -4345,6 +4388,7 @@ msgstr "文档已批准" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" msgstr "文档已取消" @@ -4519,10 +4563,18 @@ msgctxt "Audit log format" msgid "Document moved to team" msgstr "文档已移动到团队" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document no longer available" +msgstr "" + #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" msgstr "文档已不再可供签署" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Document not ready" +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document opened" @@ -4550,6 +4602,7 @@ msgstr "文档偏好设置已更新" #: apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx #: apps/remix/app/components/general/document/document-status.tsx +#: apps/remix/app/utils/toast-error-messages.ts msgid "Document rejected" msgstr "文档已被拒签" @@ -4978,6 +5031,10 @@ msgstr "例如:100" msgid "e.g. Resend (free plans)" msgstr "例如:Resend(免费套餐)" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Easy DNS setup with auto-generated DKIM and SPF records" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -5496,6 +5553,8 @@ msgid "Enter your text here" msgstr "在此输入你的文本" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Enterprise" msgstr "企业版" @@ -5562,7 +5621,6 @@ msgstr "信封已更新" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx #: apps/remix/app/components/dialogs/webhook-create-dialog.tsx #: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx #: apps/remix/app/components/general/document-signing/document-signing-auto-sign.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -5573,7 +5631,6 @@ msgstr "信封已更新" #: apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-email-field.tsx -#: apps/remix/app/components/general/document-signing/document-signing-form.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -5743,10 +5800,6 @@ msgstr "正在提取联系方式" msgid "Failed" msgstr "失败" -#: apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx -msgid "Failed to complete the document. Please try again." -msgstr "未能完成文档。请重试。" - #: apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx msgid "Failed to create document. Please try again." msgstr "创建文档失败。请重试。" @@ -6147,6 +6200,10 @@ msgstr "生成链接" msgid "German" msgstr "德语" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx msgid "Global" @@ -6379,6 +6436,10 @@ msgstr "您好,{userName} <0>({userEmail})" msgid "Hide" msgstr "隐藏" +#: packages/ui/components/document/envelope-recipient-field-tooltip.tsx +msgid "Hide field" +msgstr "" + #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" msgstr "隐藏许可证密钥" @@ -6789,6 +6850,10 @@ msgstr "当前还不是您签署的顺序。请稍后再来查看,此文档很 msgid "It's currently not your turn to sign. You will receive an email with instructions once it's your turn to sign the document." msgstr "现在还不是你签署的顺序。轮到你签署时,你会收到一封包含说明的邮件。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "It's not your turn to sign yet" +msgstr "" + #: packages/lib/constants/i18n.ts msgid "Italian" msgstr "意大利语" @@ -6907,6 +6972,10 @@ msgstr "最后更新于" msgid "Last used" msgstr "上次使用" +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +msgid "Last Used" +msgstr "" + #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Last Verified" @@ -7105,6 +7174,7 @@ msgstr "管理" msgid "Manage {0}'s profile" msgstr "管理 {0} 的资料" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." msgstr "为您的组织管理自定义 SSO 登录门户。" @@ -7531,6 +7601,10 @@ msgstr "名称为必填项" msgid "Name Settings" msgstr "姓名设置" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Named senders with defaults per team, template or document" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" msgstr "" @@ -7558,6 +7632,7 @@ msgstr "需要查看" #: apps/remix/app/components/dialogs/token-create-dialog.tsx #: apps/remix/app/components/tables/settings-security-passkey-table.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx +#: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Never" msgstr "从不" @@ -7944,6 +8019,10 @@ msgstr "模板设置完成后,将链接分享到任意位置。打开链接的 msgid "One of the documents in the current bundle has a signing role that is not compatible with the current signing experience." msgstr "当前文档包中的某个文档包含与当前签署体验不兼容的签署角色。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." +msgstr "" + #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" msgstr "只有管理员可以访问并查看该文档" @@ -8127,6 +8206,7 @@ msgstr "组织角色" msgid "Organisation Settings" msgstr "组织设置" +#: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" @@ -8673,6 +8753,11 @@ msgstr "请至少选择一名成员添加到团队。" msgid "Please select how you'd like to receive your verification code." msgstr "请选择您希望接收验证码的方式。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Please sign: Example.pdf" +msgstr "" + #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." msgstr "请尝试使用其他域名。" @@ -8859,6 +8944,10 @@ msgstr "公共模板" msgid "Public templates are connected to your public profile. Any modifications to public templates will also appear in your public profile." msgstr "公开模板与公开资料相关联。对公开模板的任何修改也会显示在你的公开资料中。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" msgstr "快速操作" @@ -9187,6 +9276,10 @@ msgstr "正在重定向" msgid "Redirecting to {0}..." msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Redirecting to your identity provider" +msgstr "" + #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx msgid "Registration Successful" @@ -9555,6 +9648,10 @@ msgstr "响应头" msgid "Rest assured, your document is strictly confidential and will never be shared. Only your signing experience will be highlighted. Share your personalized signing card to showcase your signature!" msgstr "请放心,您的文档将被严格保密,绝不会被分享。只有您的签署体验会被展示。分享您的个性化签署卡片,展示您的签名!" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Restrict sign-ins by email domain and choose the default role" +msgstr "" + #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" msgstr "受限访问" @@ -9716,8 +9813,8 @@ msgid "Search by claim ID or name" msgstr "按声明 ID 或名称搜索" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx -msgid "Search by document title, team:123 or user:123" -msgstr "按文档标题、team:123 或 user:123 搜索" +msgid "Search by document title, recipient:123, team:123 or user:123" +msgstr "" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10071,6 +10168,10 @@ msgstr "发送文档" msgid "Send Document" msgstr "发送文档" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." +msgstr "" + #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" msgstr "以此邮箱地址代表团队发送文档" @@ -10079,6 +10180,10 @@ msgstr "以此邮箱地址代表团队发送文档" msgid "Send documents to recipients immediately" msgstr "立即将文档发送给收件人" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Send emails to recipients from your domain" +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" msgstr "发送信封" @@ -10125,6 +10230,14 @@ msgstr "发件人" msgid "Sender reported" msgstr "已举报发件人" +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from app.documenso.com" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Sending from your domain" +msgstr "" + #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." msgstr "正在发送重置邮件..." @@ -10145,6 +10258,10 @@ msgstr "已发送" msgid "Sent this period" msgstr "" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Separate branding per team" +msgstr "" + #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" msgstr "会话已撤销" @@ -10250,6 +10367,7 @@ msgstr "显示使用情况和配额" #: apps/remix/app/components/general/document-signing/document-signing-name-field.tsx #: apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx #: apps/remix/app/components/general/document/document-page-view-button.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/user-profile-skeleton.tsx #: apps/remix/app/components/general/user-profile-timur.tsx #: apps/remix/app/components/tables/documents-table-action-button.tsx @@ -10421,6 +10539,10 @@ msgctxt "Signed document (adjective)" msgid "Signed" msgstr "已签署" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Signed in" +msgstr "" + #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" msgstr "签署人" @@ -10485,6 +10607,10 @@ msgstr "代签对象" msgid "Signing in..." msgstr "正在登录..." +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Signing link expired" +msgstr "" + #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx msgid "Signing Links" @@ -10537,6 +10663,10 @@ msgstr "当前已禁用注册,或您的电子邮箱域名不支持注册。" msgid "Since {0}" msgstr "自 {0} 起" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Single sign-on" +msgstr "" + #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" msgstr "站点横幅" @@ -10556,6 +10686,10 @@ msgstr "跳过" msgid "Some fields are placed on top of each other. This may complicate the signing process or cause fields to not work as expected." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Some fields were not saved" +msgstr "" + #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." msgstr "" @@ -10577,7 +10711,6 @@ msgstr "部分签署人尚未被分配签名字段。请在继续前为每位签 #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx #: apps/remix/app/components/forms/signin.tsx #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -10587,8 +10720,6 @@ msgstr "部分签署人尚未被分配签名字段。请在继续前为每位签 #: apps/remix/app/components/general/document-signing/document-signing-auth-page.tsx #: apps/remix/app/components/general/document/document-audit-log-download-button.tsx #: apps/remix/app/components/general/document/document-certificate-download-button.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx #: apps/remix/app/components/general/organisations/organisation-billing-portal-button.tsx #: apps/remix/app/components/general/organisations/organisation-invitations.tsx @@ -10611,6 +10742,7 @@ msgstr "部分签署人尚未被分配签名字段。请在继续前为每位签 #: apps/remix/app/routes/_unauthenticated+/verify-email.$token.tsx #: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts +#: apps/remix/app/utils/toast-error-messages.ts #: packages/ui/components/document/document-share-button.tsx msgid "Something went wrong" msgstr "出错了" @@ -11137,6 +11269,7 @@ msgstr "团队 URL" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/organisation-usage-panel.tsx +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -11892,6 +12025,10 @@ msgstr "" msgid "This direct link template cannot be used because one or more signers do not have a signature field assigned. Please contact the sender to update the template." msgstr "" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." +msgstr "" + #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." msgstr "此文档无法恢复。若您希望对未来文档的删除原因提出异议,请联系支持。" @@ -11920,6 +12057,10 @@ msgstr "当前无法复制此文档。请重试。" msgid "This document could not be saved as a template at this time. Please try again." msgstr "当前无法将此文档保存为模板。请重试。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has already been completed and no further signatures can be added." +msgstr "" + #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx msgid "This document has already been sent to this recipient. You can no longer edit this recipient." @@ -11938,14 +12079,26 @@ msgstr "该文档已被所有者取消,其他人已无法签署。" msgid "This document has been cancelled by the owner." msgstr "该文档已被所有者取消。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" msgstr "此文档已被某位收件人拒签" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has been rejected by a recipient and can no longer be signed." +msgstr "" + #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" msgstr "该文档已由所有收件人签署" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." +msgstr "" + #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." msgstr "此文档的收件人数量过多。请删除部分收件人,或在需要更多收件人时联系支持。" @@ -11958,6 +12111,10 @@ msgstr "此文档在您的 Documenso 账户中可用。您可以在那里查看 msgid "This document is currently a draft and has not been sent" msgstr "该文档目前是草稿,尚未发送" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." +msgstr "" + #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." msgstr "此文档正在使用旧版字段插入方式,我们建议使用新的字段插入方式以获得更精确的结果。" @@ -12673,6 +12830,18 @@ msgstr "无限文档、API 等更多功能" msgid "Unlink" msgstr "取消关联" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Unlock Branding Preferences" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx +msgid "Unlock Email Domains" +msgstr "" + +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Unlock the Organisation SSO Portal" +msgstr "" + #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" msgstr "取消固定" @@ -12846,6 +13015,10 @@ msgstr "升级" msgid "Upgrade <0>{0} to {planName}" msgstr "将 <0>{0} 升级为 {planName}" +#: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx +msgid "Upgrade Plan" +msgstr "" + #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" msgstr "升级您的套餐以上传更多文档" @@ -13332,8 +13505,8 @@ msgid "Waiting for others" msgstr "等待其他人" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts -msgid "Waiting for others to complete signing." -msgstr "正在等待其他人完成签署。" +msgid "Waiting for others to complete signing" +msgstr "" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -13662,9 +13835,7 @@ msgstr "我们未能将你的公开资料设置为公开。请重试。" msgid "We were unable to setup two-factor authentication for your account. Please ensure that you have entered your code correctly and try again." msgstr "我们未能为你的账号设置双重验证。请确保你正确输入验证码后再试。" -#: apps/remix/app/components/embed/embed-document-signing-page-v1.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx -#: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +#: apps/remix/app/utils/toast-error-messages.ts #: apps/remix/app/utils/toast-error-messages.ts msgid "We were unable to submit this document at this time. Please try again later." msgstr "目前无法提交此文档。请稍后再试。" @@ -13830,6 +14001,11 @@ msgstr "欢迎回来,我们很高兴再次见到你。" msgid "Welcome back! Here's an overview of your account." msgstr "欢迎回来!以下是您的账户概览。" +#. placeholder {0}: organisation.name +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Welcome to {0}" +msgstr "" + #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" msgstr "欢迎加入 {organisationName}" @@ -13907,6 +14083,10 @@ msgstr "撤回同意" msgid "Within limit" msgstr "" +#: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx +msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" +msgstr "" + #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" msgstr "撰写将在您的公共主页上展示的简介" @@ -14157,10 +14337,6 @@ msgstr "您可以选择启用或禁用公开个人资料。" msgid "You can copy and share these links to recipients so they can action the document." msgstr "你可以复制并分享这些链接给收件人,便于他们处理文档。" -#: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx -msgid "You can download up to {MAX_BULK_DOWNLOAD_ENVELOPES} documents at a time. Deselect some documents to continue." -msgstr "" - #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." msgstr "您可以启用访问,以默认允许所有组织成员访问此团队。" @@ -14924,6 +15100,10 @@ msgstr "您的信封已成功分发。" msgid "Your envelope has been resent successfully." msgstr "您的信封已成功重新发送。" +#: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx +msgid "Your logo on signing pages and emails" +msgstr "" + #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" msgstr "您的姓名" @@ -15057,6 +15237,10 @@ msgstr "在应用签名前,您的签名授权已过期。请重新授权后重 msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." msgstr "您的签名证书无效、已过期或缺少必需的密钥。请联系您的管理员或签名服务提供商以获取帮助。" +#: apps/remix/app/utils/toast-error-messages.ts +msgid "Your signing link has expired. Please contact the sender to request a new one." +msgstr "" + #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" msgstr "您的签名服务提供商身份验证失败" From 9dc83bdb065c532f525dc42ae279f43efccef735 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 26 Aug 2026 11:21:40 +1000 Subject: [PATCH 20/64] fix: allow zooming and dragging uploaded signatures (#3173) --- .../ui/primitives/signature-pad/helper.ts | 36 ++ .../signature-pad/signature-pad-draw.tsx | 66 ++- .../signature-pad/signature-pad-upload.tsx | 436 +++++++++++++++--- .../signature-pad/signature-tabs.tsx | 2 +- 4 files changed, 432 insertions(+), 108 deletions(-) diff --git a/packages/ui/primitives/signature-pad/helper.ts b/packages/ui/primitives/signature-pad/helper.ts index ec4c19a8e..8dbdd33eb 100644 --- a/packages/ui/primitives/signature-pad/helper.ts +++ b/packages/ui/primitives/signature-pad/helper.ts @@ -1,3 +1,39 @@ +import { SIGNATURE_MIN_COVERAGE_THRESHOLD } from '@documenso/lib/constants/signatures'; +import type { RefObject } from 'react'; + +/** + * Checks whether the signature covers enough of the canvas to be considered + * valid, by measuring the percentage of non-transparent pixels against + * SIGNATURE_MIN_COVERAGE_THRESHOLD. + */ +export const checkSignatureValidity = (element: RefObject) => { + if (!element.current) { + return false; + } + + const ctx = element.current.getContext('2d'); + + if (!ctx) { + return false; + } + + const imageData = ctx.getImageData(0, 0, element.current.width, element.current.height); + const data = imageData.data; + let filledPixels = 0; + const totalPixels = data.length / 4; + + for (let i = 0; i < data.length; i += 4) { + if (data[i + 3] > 0) { + filledPixels++; + } + } + + const filledPercentage = filledPixels / totalPixels; + const isValid = filledPercentage > SIGNATURE_MIN_COVERAGE_THRESHOLD; + + return isValid; +}; + export const average = (a: number, b: number) => (a + b) / 2; export const getSvgPathFromStroke = (points: number[][], closed = true) => { diff --git a/packages/ui/primitives/signature-pad/signature-pad-draw.tsx b/packages/ui/primitives/signature-pad/signature-pad-draw.tsx index 19bb0b867..a6981a604 100644 --- a/packages/ui/primitives/signature-pad/signature-pad-draw.tsx +++ b/packages/ui/primitives/signature-pad/signature-pad-draw.tsx @@ -1,46 +1,18 @@ import { unsafe_useEffectOnce } from '@documenso/lib/client-only/hooks/use-effect-once'; -import { SIGNATURE_CANVAS_DPI, SIGNATURE_MIN_COVERAGE_THRESHOLD } from '@documenso/lib/constants/signatures'; +import { SIGNATURE_CANVAS_DPI } from '@documenso/lib/constants/signatures'; -import { Trans } from '@lingui/react/macro'; +import { Trans, useLingui } from '@lingui/react/macro'; import { Undo2 } from 'lucide-react'; import type { StrokeOptions } from 'perfect-freehand'; import { getStroke } from 'perfect-freehand'; -import type { MouseEvent, PointerEvent, RefObject, TouchEvent } from 'react'; +import type { MouseEvent, PointerEvent, TouchEvent } from 'react'; import { useMemo, useRef, useState } from 'react'; import { cn } from '../../lib/utils'; -import { getSvgPathFromStroke } from './helper'; +import { checkSignatureValidity, getSvgPathFromStroke } from './helper'; import { Point } from './point'; import { SignaturePadColorPicker } from './signature-pad-color-picker'; -const checkSignatureValidity = (element: RefObject) => { - if (!element.current) { - return false; - } - - const ctx = element.current.getContext('2d'); - - if (!ctx) { - return false; - } - - const imageData = ctx.getImageData(0, 0, element.current.width, element.current.height); - const data = imageData.data; - let filledPixels = 0; - const totalPixels = data.length / 4; - - for (let i = 0; i < data.length; i += 4) { - if (data[i + 3] > 0) { - filledPixels++; - } - } - - const filledPercentage = filledPixels / totalPixels; - const isValid = filledPercentage > SIGNATURE_MIN_COVERAGE_THRESHOLD; - - return isValid; -}; - export type SignaturePadDrawProps = { className?: string; value: string; @@ -48,6 +20,8 @@ export type SignaturePadDrawProps = { }; export const SignaturePadDraw = ({ className, value, onChange, ...props }: SignaturePadDrawProps) => { + const { t } = useLingui(); + const $el = useRef(null); const $imageData = useRef(null); @@ -276,9 +250,19 @@ export const SignaturePadDraw = ({ className, value, onChange, ...props }: Signa {...props} /> - + -
+
+ + +
+ )} + + {hasImage && ( +
+ +
+ )} + + {isSignatureValid === false && ( +
+ + Signature is too small + +
+ )} + + {!hasImage && ( + $fileInput.current?.click()} + >
@@ -150,8 +446,8 @@ export const SignaturePadUpload = ({ className, value, onChange, ...props }: Sig
- )} -
+ + )}
); }; diff --git a/packages/ui/primitives/signature-pad/signature-tabs.tsx b/packages/ui/primitives/signature-pad/signature-tabs.tsx index 5a4ca10bf..9a9a82b47 100644 --- a/packages/ui/primitives/signature-pad/signature-tabs.tsx +++ b/packages/ui/primitives/signature-pad/signature-tabs.tsx @@ -59,7 +59,7 @@ interface TabsListProps extends React.HTMLAttributes { export function TabsList({ children, className, ...props }: TabsListProps) { return ( -
+
{children}
); From ee8360585bccc4cdb4f736d5bb8c69d5c5d61b17 Mon Sep 17 00:00:00 2001 From: Arunendra Tripathi <156455722+Arunendra21@users.noreply.github.com> Date: Wed, 26 Aug 2026 07:27:35 +0530 Subject: [PATCH 21/64] fix: render adjacent email template variables correctly (#3153) --- .../render-custom-email-template.test.ts | 32 +++++++++++++++++++ .../lib/utils/render-custom-email-template.ts | 6 +++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 packages/lib/utils/render-custom-email-template.test.ts diff --git a/packages/lib/utils/render-custom-email-template.test.ts b/packages/lib/utils/render-custom-email-template.test.ts new file mode 100644 index 000000000..b1bd4d2c7 --- /dev/null +++ b/packages/lib/utils/render-custom-email-template.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest'; + +import { renderCustomEmailTemplate } from './render-custom-email-template'; + +describe('renderCustomEmailTemplate', () => { + it('replaces a single variable', () => { + expect(renderCustomEmailTemplate('Hi {name}', { name: 'Sam' })).toBe('Hi Sam'); + }); + + it('replaces multiple variables separated by whitespace', () => { + expect( + renderCustomEmailTemplate('Hi {name}, sign at {url}', { name: 'Sam', url: 'https://x' }), + ).toBe('Hi Sam, sign at https://x'); + }); + + it('replaces adjacent variables and variables separated by a non-whitespace character', () => { + expect( + renderCustomEmailTemplate('{day}/{month}/{year}', { day: '01', month: '02', year: '2026' }), + ).toBe('01/02/2026'); + + expect( + renderCustomEmailTemplate('{firstName}-{lastName}', { + firstName: 'Ada', + lastName: 'Lovelace', + }), + ).toBe('Ada-Lovelace'); + }); + + it('leaves the key in place when the variable is not provided', () => { + expect(renderCustomEmailTemplate('Unknown {missing} here', {})).toBe('Unknown missing here'); + }); +}); diff --git a/packages/lib/utils/render-custom-email-template.ts b/packages/lib/utils/render-custom-email-template.ts index dbe7ae621..c1201bbd5 100644 --- a/packages/lib/utils/render-custom-email-template.ts +++ b/packages/lib/utils/render-custom-email-template.ts @@ -1,5 +1,9 @@ export const renderCustomEmailTemplate = >(template: string, variables: T): string => { - return template.replace(/\{(\S+)\}/g, (_, key) => { + // Match a run of non-brace, non-whitespace characters between braces. Using + // `\S+` here was greedy across braces, so placeholders separated by a + // non-whitespace character (e.g. "{day}/{month}/{year}") were captured as a + // single bogus key and left unrendered. + return template.replace(/\{([^\s{}]+)\}/g, (_, key) => { if (key in variables) { return variables[key]; } From ae4b56dd88cf8c77e21909f2aa839ef9dd95e7fa Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Thu, 27 Aug 2026 11:11:51 +1000 Subject: [PATCH 22/64] feat: optimise posthog usage and add error tracking (#3301) Disable autocapture and person profiles for anonymous users, and redact signing tokens from captured URLs. Manually wire exception capture into the signing, editor and embed flows with recipient/envelope context for debugging recipient-reported issues. Track activation events (webhooks, api tokens, direct links, embed sessions) server-side with org attribution, and drop client events already tracked in-app. --- .../dialogs/envelope-distribute-dialog.tsx | 8 ++ .../dialogs/envelope-redistribute-dialog.tsx | 9 ++ .../embed-direct-template-client-page.tsx | 17 ++++ .../embed/embed-document-signing-page-v1.tsx | 19 +++++ .../embed/embed-document-signing-page-v2.tsx | 10 +++ .../multi-sign-document-signing-view.tsx | 23 +++++ .../direct-template/direct-template-page.tsx | 9 ++ .../document-signing-checkbox-field.tsx | 23 +++++ .../document-signing-complete-dialog.tsx | 7 ++ .../document-signing-date-field.tsx | 16 ++++ .../document-signing-dropdown-field.tsx | 16 ++++ .../document-signing-email-field.tsx | 16 ++++ .../document-signing-initials-field.tsx | 16 ++++ .../document-signing-name-field.tsx | 16 ++++ .../document-signing-number-field.tsx | 16 ++++ .../document-signing-page-view-v1.tsx | 9 -- .../document-signing-radio-field.tsx | 16 ++++ .../document-signing-reject-dialog.tsx | 8 ++ .../document-signing-signature-field.tsx | 16 ++++ .../document-signing-text-field.tsx | 16 ++++ .../document-upload-button-legacy.tsx | 8 -- .../envelope-editor-fields-page-renderer.tsx | 9 ++ .../envelope-editor-upload-page.tsx | 14 ++++ .../envelope-generic-page-renderer.tsx | 9 ++ .../envelope-signer-page-renderer.tsx | 18 ++++ .../envelope-signing-complete-dialog.tsx | 20 +++-- .../envelope/envelope-drop-zone-wrapper.tsx | 13 ++- .../envelope/envelope-upload-button.tsx | 7 ++ .../general/pdf-viewer/pdf-viewer.tsx | 15 ++++ apps/remix/app/entry.client.tsx | 44 ++++++++++ apps/remix/app/root.tsx | 10 +++ .../t.$teamUrl+/documents.$id._layout.tsx | 12 +++ .../t.$teamUrl+/templates.$id._layout.tsx | 12 +++ apps/remix/app/routes/_recipient+/_layout.tsx | 8 ++ apps/remix/app/routes/embed+/_v0+/_layout.tsx | 22 +++++ .../app/routes/embed+/_v0+/direct.$token.tsx | 50 +++++++++++ .../app/routes/embed+/_v0+/sign.$token.tsx | 50 +++++++++++ .../routes/embed+/v1+/authoring+/_layout.tsx | 37 +++++++++ .../routes/embed+/v1+/multisign+/_index.tsx | 35 ++++++++ .../routes/embed+/v2+/authoring+/_layout.tsx | 12 ++- .../v2+/authoring+/envelope.create._index.tsx | 26 ++++++ .../v2+/authoring+/envelope.edit.$id.tsx | 13 +++ .../lib/client-only/hooks/use-analytics.ts | 11 ++- .../providers/envelope-editor-provider.tsx | 20 +++++ .../analytics/capture-server-event.ts | 83 +++++++++++++++++++ packages/lib/universal/fire-and-forget.ts | 14 ++++ .../api-token-router/create-api-token.ts | 21 ++++- .../trpc/server/template-router/router.ts | 24 +++++- packages/trpc/server/webhook-router/router.ts | 24 +++++- 49 files changed, 888 insertions(+), 39 deletions(-) create mode 100644 packages/lib/server-only/analytics/capture-server-event.ts create mode 100644 packages/lib/universal/fire-and-forget.ts diff --git a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx index ed495f83a..0cd5e3c4c 100644 --- a/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx +++ b/apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; @@ -71,6 +72,7 @@ export const EnvelopeDistributeDialog = ({ const { toast } = useToast(); const { t, i18n } = useLingui(); const navigate = useNavigate(); + const analytics = useAnalytics(); const [isOpen, setIsOpen] = useState(false); const [isSyncing, setIsSyncing] = useState(false); @@ -200,6 +202,12 @@ export const EnvelopeDistributeDialog = ({ } catch (err) { const error = AppError.parseError(err); + analytics.captureException(err, { + source: 'editor', + location: 'distribute_document', + envelopeId: envelope.id, + }); + const errorMessage = getDistributeErrorMessage(error.code); toast({ diff --git a/apps/remix/app/components/dialogs/envelope-redistribute-dialog.tsx b/apps/remix/app/components/dialogs/envelope-redistribute-dialog.tsx index 1a54c7893..b2d5da538 100644 --- a/apps/remix/app/components/dialogs/envelope-redistribute-dialog.tsx +++ b/apps/remix/app/components/dialogs/envelope-redistribute-dialog.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { getRecipientType } from '@documenso/lib/client-only/recipient-type'; import { AppError } from '@documenso/lib/errors/app-error'; import type { TEnvelope } from '@documenso/lib/types/envelope'; @@ -51,6 +52,7 @@ export const EnvelopeRedistributeDialog = ({ envelope, envelopeType, trigger }: const { toast } = useToast(); const { t, i18n } = useLingui(); + const analytics = useAnalytics(); const [isOpen, setIsOpen] = useState(false); @@ -95,6 +97,13 @@ export const EnvelopeRedistributeDialog = ({ envelope, envelopeType, trigger }: setIsOpen(false); } catch (err) { const error = AppError.parseError(err); + + analytics.captureException(err, { + source: 'editor', + location: 'redistribute_document', + envelopeId: envelope.id, + }); + const errorMessage = getDistributeErrorMessage(error.code); toast({ diff --git a/apps/remix/app/components/embed/embed-direct-template-client-page.tsx b/apps/remix/app/components/embed/embed-direct-template-client-page.tsx index 20a0a23fa..3e2ca1d38 100644 --- a/apps/remix/app/components/embed/embed-direct-template-client-page.tsx +++ b/apps/remix/app/components/embed/embed-direct-template-client-page.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn'; import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n'; @@ -77,6 +78,7 @@ export const EmbedDirectTemplateClientPage = ({ }: EmbedDirectTemplateClientPageProps) => { const { _ } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const [searchParams] = useSearchParams(); @@ -264,6 +266,13 @@ export const EmbedDirectTemplateClientPage = ({ const error = AppError.parseError(err); const errorMessage = getDirectTemplateErrorMessage(error.code); + analytics.captureException(err, { + source: 'embed', + location: 'direct_template', + recipientId: recipient.id, + envelopeId, + }); + toast({ title: _(errorMessage.title), description: _(errorMessage.description), @@ -308,6 +317,14 @@ export const EmbedDirectTemplateClientPage = ({ } } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'embed', + location: 'embed_init', + recipientId: recipient.id, + envelopeId, + }); + setHasFinishedInit(true); } diff --git a/apps/remix/app/components/embed/embed-document-signing-page-v1.tsx b/apps/remix/app/components/embed/embed-document-signing-page-v1.tsx index c8726ae22..739a5c8a6 100644 --- a/apps/remix/app/components/embed/embed-document-signing-page-v1.tsx +++ b/apps/remix/app/components/embed/embed-document-signing-page-v1.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useThrottleFn } from '@documenso/lib/client-only/hooks/use-throttle-fn'; import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; @@ -75,6 +76,7 @@ export const EmbedSignDocumentV1ClientPage = ({ }: EmbedSignDocumentV1ClientPageProps) => { const { _ } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const { fullName, email, signature, setFullName, setEmail, setSignature } = useRequiredDocumentSigningContext(); @@ -154,6 +156,14 @@ export const EmbedSignDocumentV1ClientPage = ({ setHasCompletedDocument(true); } catch (err) { + analytics.captureException(err, { + source: 'embed', + location: 'complete_document', + recipientId: recipient.id, + documentId, + envelopeId, + }); + if (window.parent) { window.parent.postMessage( { @@ -236,6 +246,15 @@ export const EmbedSignDocumentV1ClientPage = ({ } } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'embed', + location: 'embed_init', + recipientId: recipient.id, + documentId, + envelopeId, + }); + setHasFinishedInit(true); } diff --git a/apps/remix/app/components/embed/embed-document-signing-page-v2.tsx b/apps/remix/app/components/embed/embed-document-signing-page-v2.tsx index 969511713..55e7cb6d1 100644 --- a/apps/remix/app/components/embed/embed-document-signing-page-v2.tsx +++ b/apps/remix/app/components/embed/embed-document-signing-page-v2.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n'; import { ZSignDocumentEmbedDataSchema } from '@documenso/lib/types/embed-document-sign-schema'; import { mapSecondaryIdToDocumentId } from '@documenso/lib/utils/envelope'; @@ -25,6 +26,7 @@ export const EmbedSignDocumentV2ClientPage = ({ allowWhitelabelling = false, }: EmbedSignDocumentV2ClientPageProps) => { const { _ } = useLingui(); + const analytics = useAnalytics(); const { envelope, recipient, envelopeData, setFullName, setEmail, fullName, email } = useRequiredEnvelopeSigningContext(); @@ -170,6 +172,14 @@ export const EmbedSignDocumentV2ClientPage = ({ } } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'embed', + location: 'embed_init', + recipientId: recipient.id, + envelopeId: envelope.id, + }); + setHasFinishedInit(true); } diff --git a/apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx b/apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx index 15902715d..8964033a6 100644 --- a/apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx +++ b/apps/remix/app/components/embed/multisign/multi-sign-document-signing-view.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { getDocumentDataUrlForPdfViewer } from '@documenso/lib/utils/envelope-download'; @@ -57,6 +58,7 @@ export const MultiSignDocumentSigningView = ({ }: MultiSignDocumentSigningViewProps) => { const { _ } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const { fullName, email, signature, setFullName, setSignature } = useRequiredDocumentSigningContext(); @@ -101,6 +103,13 @@ export const MultiSignDocumentSigningView = ({ console.error(err); + analytics.captureException(err, { + source: 'embed', + location: 'sign_field', + recipientId, + documentId: document?.id, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while signing the document.`), @@ -120,6 +129,13 @@ export const MultiSignDocumentSigningView = ({ } console.error(err); + + analytics.captureException(err, { + source: 'embed', + location: 'remove_field', + recipientId, + documentId: document?.id, + }); } }; @@ -140,6 +156,13 @@ export const MultiSignDocumentSigningView = ({ recipientId, }); } catch (err) { + analytics.captureException(err, { + source: 'embed', + location: 'complete_document', + recipientId, + documentId: document?.id, + }); + onDocumentError?.(); const error = AppError.parseError(err); diff --git a/apps/remix/app/components/general/direct-template/direct-template-page.tsx b/apps/remix/app/components/general/direct-template/direct-template-page.tsx index 9f6ea47dc..58ea7d50f 100644 --- a/apps/remix/app/components/general/direct-template/direct-template-page.tsx +++ b/apps/remix/app/components/general/direct-template/direct-template-page.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles'; import { AppError } from '@documenso/lib/errors/app-error'; import type { TTemplate } from '@documenso/lib/types/template'; @@ -41,6 +42,7 @@ export const DirectTemplatePageView = ({ const { _ } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const { email, fullName, setEmail } = useRequiredDocumentSigningContext(); const { recipient, setRecipient } = useRequiredDocumentSigningAuthContext(); @@ -124,6 +126,13 @@ export const DirectTemplatePageView = ({ const error = AppError.parseError(err); const errorMessage = getDirectTemplateErrorMessage(error.code); + analytics.captureException(err, { + source: 'signing', + location: 'direct_template', + recipientId: directTemplateRecipient.id, + envelopeId: template.envelopeId, + }); + toast({ title: _(errorMessage.title), description: _(errorMessage.description), diff --git a/apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx index 7e9a7adb6..dcf2e2d81 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-checkbox-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -39,6 +40,7 @@ export const DocumentSigningCheckboxField = ({ const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -126,6 +128,13 @@ export const DocumentSigningCheckboxField = ({ console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -157,6 +166,13 @@ export const DocumentSigningCheckboxField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), @@ -216,6 +232,13 @@ export const DocumentSigningCheckboxField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while updating the signature.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx b/apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx index 41abb63f1..f5508f727 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { type TRecipientAccessAuth, ZDocumentAccessAuthSchema } from '@documenso/lib/types/document-auth'; import { fieldsContainUnsignedRequiredField } from '@documenso/lib/utils/advanced-fields-helpers'; @@ -88,6 +89,7 @@ export const DocumentSigningCompleteDialog = ({ position, disableNameInput = false, }: DocumentSigningCompleteDialogProps) => { + const analytics = useAnalytics(); const { t, i18n } = useLingui(); const { toast } = useToast(); @@ -179,6 +181,11 @@ export const DocumentSigningCompleteDialog = ({ return; } + analytics.captureException(error, { + source: 'signing', + location: 'complete_document', + }); + // This dialog owns the completion error toast for every signing surface // so the user gets a specific, actionable message. Callers should run // their own side effects (e.g. embeds posting document-error) and diff --git a/apps/remix/app/components/general/document-signing/document-signing-date-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-date-field.tsx index 1d05d3017..51135630c 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-date-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-date-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { convertToLocalSystemFormat, DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; @@ -39,6 +40,7 @@ export const DocumentSigningDateField = ({ const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -85,6 +87,13 @@ export const DocumentSigningDateField = ({ console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -113,6 +122,13 @@ export const DocumentSigningDateField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx index 2ac26f87c..549eb6128 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-dropdown-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -35,6 +36,7 @@ export const DocumentSigningDropdownField = ({ const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -86,6 +88,13 @@ export const DocumentSigningDropdownField = ({ console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -120,6 +129,13 @@ export const DocumentSigningDropdownField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-email-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-email-field.tsx index 408914336..8e88d99be 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-email-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-email-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -33,6 +34,7 @@ export const DocumentSigningEmailField = ({ field, onSignField, onUnsignField }: const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { email: providedEmail } = useRequiredDocumentSigningContext(); @@ -78,6 +80,13 @@ export const DocumentSigningEmailField = ({ field, onSignField, onUnsignField }: console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -106,6 +115,13 @@ export const DocumentSigningEmailField = ({ field, onSignField, onUnsignField }: } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx index 6a9b74a3d..b79bf40fe 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-initials-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -38,6 +39,7 @@ export const DocumentSigningInitialsField = ({ const { toast } = useToast(); const { _ } = useLingui(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { fullName } = useRequiredDocumentSigningContext(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -84,6 +86,13 @@ export const DocumentSigningInitialsField = ({ console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -112,6 +121,13 @@ export const DocumentSigningInitialsField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-name-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-name-field.tsx index 71ebe6995..0b4660e5d 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-name-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-name-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -39,6 +40,7 @@ export const DocumentSigningNameField = ({ field, onSignField, onUnsignField }: const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { fullName: providedFullName, setFullName: setProvidedFullName } = useRequiredDocumentSigningContext(); @@ -116,6 +118,13 @@ export const DocumentSigningNameField = ({ field, onSignField, onUnsignField }: console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -144,6 +153,13 @@ export const DocumentSigningNameField = ({ field, onSignField, onUnsignField }: } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-number-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-number-field.tsx index 01f0e9714..0dd92c0ed 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-number-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-number-field.tsx @@ -1,4 +1,5 @@ import { validateNumberField } from '@documenso/lib/advanced-fields-validation/validate-number'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -47,6 +48,7 @@ export const DocumentSigningNumberField = ({ field, onSignField, onUnsignField } const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -142,6 +144,13 @@ export const DocumentSigningNumberField = ({ field, onSignField, onUnsignField } console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -193,6 +202,13 @@ export const DocumentSigningNumberField = ({ field, onSignField, onUnsignField } } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx b/apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx index 1979c63a2..4fa8077a0 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx @@ -1,4 +1,3 @@ -import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats'; import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer'; import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones'; @@ -83,8 +82,6 @@ export const DocumentSigningPageViewV1 = ({ ? authUser.twoFactorEnabled && authUser.email === recipient.email : false; - const analytics = useAnalytics(); - const [selectedSignerId, setSelectedSignerId] = useState(allRecipients?.[0]?.id); const [isExpanded, setIsExpanded] = useState(false); @@ -118,12 +115,6 @@ export const DocumentSigningPageViewV1 = ({ await completeDocumentWithToken(payload); - analytics.capture('App: Recipient has completed signing', { - signerId: recipient.id, - documentId: document.id, - timestamp: new Date().toISOString(), - }); - if (documentMeta?.redirectUrl) { window.location.href = documentMeta.redirectUrl; } else { diff --git a/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx index e9d6af196..b155344db 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-radio-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -31,6 +32,7 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }: const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, targetSigner, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -91,6 +93,13 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }: console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -120,6 +129,13 @@ export const DocumentSigningRadioField = ({ field, onSignField, onUnsignField }: } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the selection.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx b/apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx index ba70ad048..f0d07eac8 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-reject-dialog.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { trpc } from '@documenso/trpc/react'; import { Button } from '@documenso/ui/primitives/button'; import { @@ -41,6 +42,7 @@ export function DocumentSigningRejectDialog({ }: DocumentSigningRejectDialogProps) { const { t } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const [searchParams] = useSearchParams(); const [isOpen, setIsOpen] = useState(false); @@ -76,6 +78,12 @@ export function DocumentSigningRejectDialog({ window.location.href = `/sign/${token}/rejected`; } } catch (err) { + analytics.captureException(err, { + source: 'signing', + location: 'reject_document', + documentId, + }); + toast({ title: t`Error`, description: t`An error occurred while rejecting the document. Please try again.`, diff --git a/apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx index 3ff8b1d68..ecab0b1bc 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-signature-field.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -47,6 +48,7 @@ export const DocumentSigningSignatureField = ({ const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient } = useDocumentSigningRecipientContext(); @@ -157,6 +159,13 @@ export const DocumentSigningSignatureField = ({ console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while signing the document.`), @@ -183,6 +192,13 @@ export const DocumentSigningSignatureField = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the signature.`), diff --git a/apps/remix/app/components/general/document-signing/document-signing-text-field.tsx b/apps/remix/app/components/general/document-signing/document-signing-text-field.tsx index f3f12063a..b99b7337c 100644 --- a/apps/remix/app/components/general/document-signing/document-signing-text-field.tsx +++ b/apps/remix/app/components/general/document-signing/document-signing-text-field.tsx @@ -1,4 +1,5 @@ import { validateTextField } from '@documenso/lib/advanced-fields-validation/validate-text'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { DO_NOT_INVALIDATE_QUERY_ON_MUTATION } from '@documenso/lib/constants/trpc'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth'; @@ -50,6 +51,7 @@ export const DocumentSigningTextField = ({ field, onSignField, onUnsignField }: const { _ } = useLingui(); const { toast } = useToast(); const { revalidate } = useRevalidator(); + const analytics = useAnalytics(); const { recipient, isAssistantMode } = useDocumentSigningRecipientContext(); @@ -170,6 +172,13 @@ export const DocumentSigningTextField = ({ field, onSignField, onUnsignField }: console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: isAssistantMode @@ -200,6 +209,13 @@ export const DocumentSigningTextField = ({ field, onSignField, onUnsignField }: } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'remove_field', + fieldType: field.type, + recipientId: field.recipientId, + }); + toast({ title: _(msg`Error`), description: _(msg`An error occurred while removing the field.`), diff --git a/apps/remix/app/components/general/document/document-upload-button-legacy.tsx b/apps/remix/app/components/general/document/document-upload-button-legacy.tsx index c53cd93c0..5be052dfc 100644 --- a/apps/remix/app/components/general/document/document-upload-button-legacy.tsx +++ b/apps/remix/app/components/general/document/document-upload-button-legacy.tsx @@ -1,5 +1,4 @@ import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; -import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { useSession } from '@documenso/lib/client-only/providers/session'; import { DEFAULT_DOCUMENT_TIME_ZONE, TIME_ZONES } from '@documenso/lib/constants/time-zones'; @@ -38,7 +37,6 @@ export const DocumentUploadButtonLegacy = ({ className, type }: DocumentUploadBu const team = useCurrentTeam(); const navigate = useNavigate(); - const analytics = useAnalytics(); const organisation = useCurrentOrganisation(); const userTimezone = @@ -103,12 +101,6 @@ export const DocumentUploadButtonLegacy = ({ className, type }: DocumentUploadBu description: _(msg`Your document has been uploaded successfully.`), duration: 5000, }); - - analytics.capture('App: Document Uploaded', { - userId: user.id, - documentId: id, - timestamp: new Date().toISOString(), - }); } // Handle legacy template creation. diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx index 698f83651..c9deb51ad 100644 --- a/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx +++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useDebouncedValue } from '@documenso/lib/client-only/hooks/use-debounced-value'; import type { TLocalField } from '@documenso/lib/client-only/hooks/use-editor-fields'; import { usePageRenderer } from '@documenso/lib/client-only/hooks/use-page-renderer'; @@ -39,6 +40,7 @@ import { EnvelopeRecipientSelectorCommand } from './envelope-recipient-selector' export const EnvelopeEditorFieldsPageRenderer = ({ pageData }: { pageData: PageRenderData }) => { const { t, i18n } = useLingui(); + const analytics = useAnalytics(); const { envelope, editorFields, getRecipientColorKey } = useCurrentEnvelopeEditor(); const { currentEnvelopeItem, setRenderError } = useCurrentEnvelopeRender(); @@ -276,6 +278,13 @@ export const EnvelopeEditorFieldsPageRenderer = ({ pageData }: { pageData: PageR unsafeRenderFieldOnLayer(field); } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'editor', + location: 'envelope_page_render', + envelopeId: envelope.id, + }); + setRenderError(true); } }; diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx index c6fb38938..73493c385 100644 --- a/apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx +++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx @@ -1,4 +1,5 @@ import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useEnvelopeAutosave } from '@documenso/lib/client-only/hooks/use-envelope-autosave'; import { useCurrentEnvelopeEditor } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; @@ -45,6 +46,7 @@ export const EnvelopeEditorUploadPage = () => { const { t, i18n } = useLingui(); const { maximumEnvelopeItemCount, remaining } = useLimits(); const { toast } = useToast(); + const analytics = useAnalytics(); const { envelope, @@ -213,6 +215,12 @@ export const EnvelopeEditorUploadPage = () => { const { data } = await createPromise.catch((error) => { console.error(error); + analytics.captureException(error, { + source: isEmbedded ? 'embed' : 'editor', + location: 'create_envelope_items', + envelopeId: envelope.id, + }); + // Set error state on files in batch upload. setLocalFiles((prev) => prev.map((uploadingFile) => @@ -290,6 +298,12 @@ export const EnvelopeEditorUploadPage = () => { } catch (error) { console.error(error); + analytics.captureException(error, { + source: isEmbedded ? 'embed' : 'editor', + location: 'replace_pdf', + envelopeId: envelope.id, + }); + toast({ title: t`Replace failed`, description: t`Something went wrong while replacing the PDF`, diff --git a/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx b/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx index 7fd72c703..015012a73 100644 --- a/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx +++ b/apps/remix/app/components/general/envelope-editor/envelope-generic-page-renderer.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { usePageRenderer } from '@documenso/lib/client-only/hooks/use-page-renderer'; import { type PageRenderData, @@ -18,6 +19,7 @@ type GenericLocalField = TEnvelope['fields'][number] & { export const EnvelopeGenericPageRenderer = ({ pageData }: { pageData: PageRenderData }) => { const { i18n } = useLingui(); + const analytics = useAnalytics(); const { envelopeStatus, @@ -114,6 +116,13 @@ export const EnvelopeGenericPageRenderer = ({ pageData }: { pageData: PageRender unsafeRenderFieldOnLayer(field); } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'editor', + location: 'envelope_page_render', + envelopeId: currentEnvelopeItem?.envelopeId, + }); + setRenderError(true); } }; diff --git a/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx b/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx index 8caab7ac0..1c5c54ca0 100644 --- a/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx +++ b/apps/remix/app/components/general/envelope-signing/envelope-signer-page-renderer.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { usePageRenderer } from '@documenso/lib/client-only/hooks/use-page-renderer'; import { type PageRenderData, @@ -53,6 +54,7 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD const { executeActionAuthProcedure } = useRequiredDocumentSigningAuthContext(); const { toast } = useToast(); + const analytics = useAnalytics(); const { envelopeData, @@ -426,6 +428,14 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD unsafeRenderFieldOnLayer(unparsedField, fieldCanvasStyleCache); } catch (err) { console.error(err); + + analytics.captureException(err, { + source: 'signing', + location: 'page_render', + recipientId: recipient.id, + envelopeId: envelope.id, + }); + setRenderError(true); } }; @@ -507,6 +517,14 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD } catch (err) { console.error(err); + analytics.captureException(err, { + source: 'signing', + location: 'sign_field', + fieldType: payload.type, + recipientId: recipient.id, + envelopeId: envelope.id, + }); + toast({ title: t`Error`, description: t`An error occurred while signing the field.`, diff --git a/apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx b/apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx index 29f1dbeee..c522419ca 100644 --- a/apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx +++ b/apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx @@ -118,12 +118,6 @@ export const EnvelopeSignerCompleteDialog = () => { title: t`Document already signed`, description: t`This document was already signed and no further action was taken.`, }); - } else { - analytics.capture('App: Recipient has completed signing', { - signerId: recipient.id, - documentId: envelope.id, - timestamp: new Date().toISOString(), - }); } if (onDocumentCompleted) { @@ -148,6 +142,13 @@ export const EnvelopeSignerCompleteDialog = () => { const error = AppError.parseError(err); if (error.code !== AppErrorCode.TWO_FACTOR_AUTH_FAILED) { + analytics.captureException(err, { + source: 'signing', + location: 'complete_document', + recipientId: recipient.id, + envelopeId: envelope.id, + }); + onDocumentError?.(); } @@ -221,6 +222,13 @@ export const EnvelopeSignerCompleteDialog = () => { } catch (err) { console.log('err', err); + analytics.captureException(err, { + source: 'signing', + location: 'complete_document_next_signer', + recipientId: recipient.id, + envelopeId: envelope.id, + }); + onDocumentError?.(); // Rethrow so DocumentSigningCompleteDialog can toast a specific diff --git a/apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx b/apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx index 3b1a0b188..cf7bfb67c 100644 --- a/apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx +++ b/apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx @@ -93,14 +93,6 @@ export const EnvelopeDropZoneWrapper = ({ children, type, className }: EnvelopeD duration: 5000, }); - if (type === EnvelopeType.DOCUMENT) { - analytics.capture('App: Document Uploaded', { - userId: user.id, - documentId: id, - timestamp: new Date().toISOString(), - }); - } - const pathPrefix = type === EnvelopeType.DOCUMENT ? formatDocumentsPath(team.url) : formatTemplatesPath(team.url); const aiQueryParam = team.preferences.aiFeaturesEnabled ? '?ai=true' : ''; @@ -109,6 +101,11 @@ export const EnvelopeDropZoneWrapper = ({ children, type, className }: EnvelopeD } catch (err) { const error = AppError.parseError(err); + analytics.captureException(err, { + source: 'editor', + location: 'upload_document', + }); + const errorMessage = getUploadErrorMessage(error.code); toast({ diff --git a/apps/remix/app/components/general/envelope/envelope-upload-button.tsx b/apps/remix/app/components/general/envelope/envelope-upload-button.tsx index 25611fd40..c177eb8fb 100644 --- a/apps/remix/app/components/general/envelope/envelope-upload-button.tsx +++ b/apps/remix/app/components/general/envelope/envelope-upload-button.tsx @@ -1,4 +1,5 @@ import { useLimits } from '@documenso/ee/server-only/limits/provider/client'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useCurrentOrganisation } from '@documenso/lib/client-only/providers/organisation'; import { useSession } from '@documenso/lib/client-only/providers/session'; import { TIME_ZONES } from '@documenso/lib/constants/time-zones'; @@ -34,6 +35,7 @@ export const EnvelopeUploadButton = ({ className, type, folderId }: EnvelopeUplo const { t, i18n } = useLingui(); const { toast } = useToast(); const { user } = useSession(); + const analytics = useAnalytics(); const team = useCurrentTeam(); @@ -112,6 +114,11 @@ export const EnvelopeUploadButton = ({ className, type, folderId }: EnvelopeUplo console.error(err); + analytics.captureException(err, { + source: 'editor', + location: 'upload_document', + }); + const errorMessage = getUploadErrorMessage(error.code); toast({ diff --git a/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx b/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx index c795485f2..3fa39a232 100644 --- a/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx +++ b/apps/remix/app/components/general/pdf-viewer/pdf-viewer.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import type { ImageLoadingState, PageRenderData } from '@documenso/lib/client-only/providers/envelope-render-provider'; import { PDF_VIEWER_PAGE_CLASSNAME } from '@documenso/lib/constants/pdf-viewer'; import { cn } from '@documenso/ui/lib/utils'; @@ -68,6 +69,7 @@ export default function PDFViewer({ }: PDFViewerProps) { const { t } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const $el = useRef(null); @@ -150,6 +152,11 @@ export default function PDFViewer({ console.error(err); setLoadingState('error'); + analytics.captureException(err, { + source: 'pdf_viewer', + location: 'pdf_load', + }); + toast({ title: t`Error`, description: t`An error occurred while loading the document.`, @@ -366,6 +373,8 @@ const PdfViewerPage = ({ * Manages rendering a page from a pdf. */ const usePdfPageImage = ({ pageNumber, pdf, scale, scaledWidth, scaledHeight }: PdfViewerPageProps) => { + const analytics = useAnalytics(); + const [imageLoadingState, setImageLoadingState] = useState('loading'); const [imageUrl, setImageUrl] = useState(''); @@ -457,6 +466,12 @@ const usePdfPageImage = ({ pageNumber, pdf, scale, scaledWidth, scaledHeight }: if (!isCancelled) { console.error(err); + + analytics.captureException(err, { + source: 'pdf_viewer', + location: 'pdf_page_render', + }); + setImageLoadingState('error'); } } finally { diff --git a/apps/remix/app/entry.client.tsx b/apps/remix/app/entry.client.tsx index f76430676..57daa65e3 100644 --- a/apps/remix/app/entry.client.tsx +++ b/apps/remix/app/entry.client.tsx @@ -18,6 +18,23 @@ import './utils/polyfills/promise-with-resolvers'; * the page early, leaving dead event handlers (broken dropdowns, native form * submits). */ +/** + * Signing and direct template URLs contain recipient tokens which must never + * be sent to PostHog. Recipient context is attached explicitly via + * `recipientId` where needed instead. + */ +const redactTokensFromUrl = (value: string) => { + return value.replace(/(\/(?:sign|d|direct)\/)([^/?#]+)/g, '$1:token'); +}; + +const URL_EVENT_PROPERTIES = [ + '$current_url', + '$pathname', + '$referrer', + '$initial_referrer', + '$prev_pageview_pathname', +] as const; + function initPosthog() { const postHogConfig = extractPostHogConfig(); @@ -25,7 +42,34 @@ function initPosthog() { void import('posthog-js').then(({ default: posthog }) => { posthog.init(postHogConfig.key, { api_host: postHogConfig.host, + // Only create person profiles for identified (authenticated) users, + // anonymous recipients on signing pages stay anonymous. + person_profiles: 'identified_only', + // Explicit events only, autocapture on signing pages blows up usage + // without providing actionable data. + autocapture: false, + capture_pageview: true, + capture_pageleave: false, capture_exceptions: true, + before_send: (event) => { + if (!event) { + return null; + } + + for (const property of URL_EVENT_PROPERTIES) { + const value = event.properties?.[property]; + + if (typeof value === 'string') { + event.properties[property] = redactTokensFromUrl(value); + } + } + + if (event.$set_once && typeof event.$set_once['$initial_current_url'] === 'string') { + event.$set_once['$initial_current_url'] = redactTokensFromUrl(event.$set_once['$initial_current_url']); + } + + return event; + }, }); }); } diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx index 75b37495c..baffaa6ec 100644 --- a/apps/remix/app/root.tsx +++ b/apps/remix/app/root.tsx @@ -1,4 +1,5 @@ import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { SessionProvider } from '@documenso/lib/client-only/providers/session'; import { getBasePath } from '@documenso/lib/constants/app'; import { APP_I18N_OPTIONS, type SupportedLanguageCodes } from '@documenso/lib/constants/i18n'; @@ -9,6 +10,7 @@ import { getOrganisationSession } from '@documenso/trpc/server/organisation-rout import { Toaster } from '@documenso/ui/primitives/toaster'; import { TooltipProvider } from '@documenso/ui/primitives/tooltip'; import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'; +import { useEffect } from 'react'; import { data, isRouteErrorResponse, @@ -200,11 +202,19 @@ export default function App() { } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + const analytics = useAnalytics(); + const errorCode = isRouteErrorResponse(error) ? error.status : 500; if (errorCode !== 404) { console.error('[RootErrorBoundary]', error); } + useEffect(() => { + if (errorCode !== 404) { + analytics.captureException(error, { source: 'app', location: 'root_boundary' }); + } + }, [error]); + return ; } diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._layout.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._layout.tsx index 578658441..0931f0474 100644 --- a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._layout.tsx +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._layout.tsx @@ -1,4 +1,5 @@ import { getSession } from '@documenso/auth/server/lib/utils/get-session'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { getEnvelopeById } from '@documenso/lib/server-only/envelope/get-envelope-by-id'; import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team'; @@ -7,6 +8,7 @@ import { msg } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; import { EnvelopeType } from '@prisma/client'; import { ChevronLeftIcon } from 'lucide-react'; +import { useEffect } from 'react'; import type { ShouldRevalidateFunctionArgs } from 'react-router'; import { isRouteErrorResponse, Link, Outlet, redirect } from 'react-router'; @@ -66,8 +68,18 @@ export default function DocumentsLayout() { } export function ErrorBoundary({ error, params }: Route.ErrorBoundaryProps) { + const analytics = useAnalytics(); + const errorCode = isRouteErrorResponse(error) ? error.status : 500; + useEffect(() => { + analytics.captureException(error, { + source: 'editor', + location: 'editor_layout_boundary', + envelopeId: params.id, + }); + }, [error]); + const errorCodeMap = { 404: { subHeading: msg`404 Document not found`, diff --git a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates.$id._layout.tsx b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates.$id._layout.tsx index 3edd8fd34..b0faefe1b 100644 --- a/apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates.$id._layout.tsx +++ b/apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates.$id._layout.tsx @@ -1,4 +1,5 @@ import { getSession } from '@documenso/auth/server/lib/utils/get-session'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { getEnvelopeById } from '@documenso/lib/server-only/envelope/get-envelope-by-id'; import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team'; @@ -8,6 +9,7 @@ import { msg } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; import { EnvelopeType } from '@prisma/client'; import { ChevronLeftIcon } from 'lucide-react'; +import { useEffect } from 'react'; import { isRouteErrorResponse, Link, Outlet, redirect, type ShouldRevalidateFunctionArgs } from 'react-router'; import { GenericErrorLayout } from '~/components/general/generic-error-layout'; @@ -84,8 +86,18 @@ export default function TemplatesLayout() { } export function ErrorBoundary({ error, params }: Route.ErrorBoundaryProps) { + const analytics = useAnalytics(); + const errorCode = isRouteErrorResponse(error) ? error.status : 500; + useEffect(() => { + analytics.captureException(error, { + source: 'editor', + location: 'editor_layout_boundary', + envelopeId: params.id, + }); + }, [error]); + const errorCodeMap = { 404: { subHeading: msg`404 Template not found`, diff --git a/apps/remix/app/routes/_recipient+/_layout.tsx b/apps/remix/app/routes/_recipient+/_layout.tsx index 940218adb..fde4a7998 100644 --- a/apps/remix/app/routes/_recipient+/_layout.tsx +++ b/apps/remix/app/routes/_recipient+/_layout.tsx @@ -1,3 +1,4 @@ +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { useOptionalSession } from '@documenso/lib/client-only/providers/session'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; @@ -5,6 +6,7 @@ import { i18n } from '@lingui/core'; import { msg } from '@lingui/core/macro'; import { Trans } from '@lingui/react/macro'; import { ChevronLeft } from 'lucide-react'; +import { useEffect } from 'react'; import { isRouteErrorResponse, Link, Outlet } from 'react-router'; import { Header as AuthenticatedHeader } from '~/components/general/app-header'; import { GenericErrorLayout } from '~/components/general/generic-error-layout'; @@ -48,8 +50,14 @@ export default function RecipientLayout({ matches }: Route.ComponentProps) { } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + const analytics = useAnalytics(); + const errorCode = isRouteErrorResponse(error) ? error.status : 500; + useEffect(() => { + analytics.captureException(error, { source: 'signing', location: 'recipient_layout_boundary' }); + }, [error]); + return ( { + const isExpectedEmbedResponse = + isRouteErrorResponse(error) && + [ + 'embed-authentication-required', + 'embed-paywall', + 'embed-waiting-for-turn', + 'embed-recipient-expired', + 'embed-document-rejected', + 'embed-document-completed', + ].includes(error.data?.type); + + if (isExpectedEmbedResponse) { + return; + } + + analytics.captureException(error, { source: 'embed', location: 'embed_layout_boundary' }); + }, [error]); + if (isRouteErrorResponse(error)) { if (error.status === 401 && error.data.type === 'embed-authentication-required') { return ( diff --git a/apps/remix/app/routes/embed+/_v0+/direct.$token.tsx b/apps/remix/app/routes/embed+/_v0+/direct.$token.tsx index b041e01ca..f8e6d0630 100644 --- a/apps/remix/app/routes/embed+/_v0+/direct.$token.tsx +++ b/apps/remix/app/routes/embed+/_v0+/direct.$token.tsx @@ -2,11 +2,13 @@ import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session import { EnvelopeRenderProvider } from '@documenso/lib/client-only/providers/envelope-render-provider'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { getEnvelopeForDirectTemplateSigning } from '@documenso/lib/server-only/envelope/get-envelope-for-direct-template-signing'; import { getEnvelopeRequiredAccessData } from '@documenso/lib/server-only/envelope/get-envelope-required-access-data'; import { getOrganisationClaimByTeamId } from '@documenso/lib/server-only/organisation/get-organisation-claims'; import { getTemplateByDirectLinkToken } from '@documenso/lib/server-only/template/get-template-by-direct-link-token'; import { DocumentAccessAuth } from '@documenso/lib/types/document-auth'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth'; import { prisma } from '@documenso/prisma'; import { data } from 'react-router'; @@ -93,6 +95,30 @@ async function handleV1Loader({ params, request }: Route.LoaderArgs) { const fields = template.fields.filter((field) => field.recipientId === directTemplateRecipientId); + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: template.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + organisationId: team?.organisationId, + teamId: template.teamId, + properties: { + type: 'signing', + version: 'v0', + recipientId: recipient.id, + envelopeId: template.envelopeId, + }, + }); + }); + return { token, user, @@ -194,6 +220,30 @@ async function handleV2Loader({ params, request }: Route.LoaderArgs) { ); } + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: envelope.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + organisationId: team?.organisationId, + teamId: envelope.teamId, + properties: { + type: 'signing', + version: 'v0', + recipientId: recipient.id, + envelopeId: envelope.id, + }, + }); + }); + return { token, user, diff --git a/apps/remix/app/routes/embed+/_v0+/sign.$token.tsx b/apps/remix/app/routes/embed+/_v0+/sign.$token.tsx index 997bf4e4a..f36ced9af 100644 --- a/apps/remix/app/routes/embed+/_v0+/sign.$token.tsx +++ b/apps/remix/app/routes/embed+/_v0+/sign.$token.tsx @@ -2,6 +2,7 @@ import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session import { EnvelopeRenderProvider } from '@documenso/lib/client-only/providers/envelope-render-provider'; import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token'; import { viewedDocument } from '@documenso/lib/server-only/document/viewed-document'; import { getEnvelopeForRecipientSigning } from '@documenso/lib/server-only/envelope/get-envelope-for-recipient-signing'; @@ -13,6 +14,7 @@ import { getIsRecipientsTurnToSign } from '@documenso/lib/server-only/recipient/ import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token'; import { getRecipientsForAssistant } from '@documenso/lib/server-only/recipient/get-recipients-for-assistant'; import { DocumentAccessAuth } from '@documenso/lib/types/document-auth'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { isDocumentCompleted } from '@documenso/lib/utils/document'; import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth'; import { isRecipientExpired } from '@documenso/lib/utils/recipients'; @@ -139,6 +141,30 @@ async function handleV1Loader({ params, request }: Route.LoaderArgs) { }) : []; + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: document.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + organisationId: team?.organisationId, + teamId: document.teamId, + properties: { + type: 'signing', + version: 'v0', + recipientId: recipient.id, + envelopeId: document.envelopeId, + }, + }); + }); + return { token, user, @@ -272,6 +298,30 @@ async function handleV2Loader({ params, request }: Route.LoaderArgs) { recipientAccessAuth: derivedRecipientAccessAuth, }).catch(() => null); + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: envelope.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + organisationId: team?.organisationId, + teamId: envelope.teamId, + properties: { + type: 'signing', + version: 'v0', + recipientId: recipient.id, + envelopeId: envelope.id, + }, + }); + }); + return { token, user, diff --git a/apps/remix/app/routes/embed+/v1+/authoring+/_layout.tsx b/apps/remix/app/routes/embed+/v1+/authoring+/_layout.tsx index d55fe5e5c..b048d5663 100644 --- a/apps/remix/app/routes/embed+/v1+/authoring+/_layout.tsx +++ b/apps/remix/app/routes/embed+/v1+/authoring+/_layout.tsx @@ -1,8 +1,11 @@ import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token'; import { getOrganisationClaimByTeamId } from '@documenso/lib/server-only/organisation/get-organisation-claims'; import { ZBaseEmbedAuthoringSchema } from '@documenso/lib/types/embed-authoring-base-schema'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { dynamicActivate } from '@documenso/lib/utils/i18n'; +import { prisma } from '@documenso/prisma'; import { TrpcProvider } from '@documenso/trpc/react'; import { Spinner } from '@documenso/ui/primitives/spinner'; import { Trans } from '@lingui/react/macro'; @@ -35,6 +38,40 @@ export const loader = async ({ request }: Route.LoaderArgs) => { }); allowEmbedAuthoringWhiteLabel = organisationClaim.flags.embedAuthoringWhiteLabel ?? false; + + // Derive the kind of authoring session from the child route path, e.g. + // /embed/v1/authoring/document/create -> resource 'document', mode 'create'. + // Completed and error pages are not new sessions and are skipped. + const [resource, mode] = url.pathname.split('/').filter(Boolean).slice(3); + + const isAuthoringSession = + (resource === 'document' || resource === 'template') && (mode === 'create' || mode === 'edit'); + + if (isAuthoringSession) { + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: result.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: result.userId, + organisationId: team?.organisationId, + teamId: result.teamId, + properties: { + type: 'authoring', + version: 'v1', + resource, + mode, + }, + }); + }); + } } return { diff --git a/apps/remix/app/routes/embed+/v1+/multisign+/_index.tsx b/apps/remix/app/routes/embed+/v1+/multisign+/_index.tsx index 4bafee963..1759a6121 100644 --- a/apps/remix/app/routes/embed+/v1+/multisign+/_index.tsx +++ b/apps/remix/app/routes/embed+/v1+/multisign+/_index.tsx @@ -1,8 +1,11 @@ import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { getDocumentAndSenderByToken } from '@documenso/lib/server-only/document/get-document-by-token'; import { getOrganisationClaimByTeamId } from '@documenso/lib/server-only/organisation/get-organisation-claims'; import { getRecipientByToken } from '@documenso/lib/server-only/recipient/get-recipient-by-token'; import { ZSignDocumentEmbedDataSchema } from '@documenso/lib/types/embed-document-sign-schema'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; +import { prisma } from '@documenso/prisma'; import { Trans } from '@lingui/react/macro'; import { SigningStatus } from '@prisma/client'; import { useEffect, useLayoutEffect, useState } from 'react'; @@ -42,6 +45,15 @@ export async function loader({ request }: Route.LoaderArgs) { const firstDocument = envelopes[0]?.document; if (!firstDocument) { + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + properties: { + type: 'signing', + version: 'v1', + }, + }); + return superLoaderJson({ envelopes, user, @@ -55,6 +67,29 @@ export async function loader({ request }: Route.LoaderArgs) { const allowWhitelabelling = organisationClaim.flags.embedSigningWhiteLabel; const hidePoweredBy = organisationClaim.flags.hidePoweredBy; + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { + id: firstDocument.teamId, + }, + select: { + organisationId: true, + }, + }); + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: user?.id, + organisationId: team?.organisationId, + teamId: firstDocument.teamId, + properties: { + type: 'signing', + version: 'v1', + envelopeId: firstDocument.envelopeId, + }, + }); + }); + return superLoaderJson({ envelopes, user, diff --git a/apps/remix/app/routes/embed+/v2+/authoring+/_layout.tsx b/apps/remix/app/routes/embed+/v2+/authoring+/_layout.tsx index eb8b81ef4..87ded302a 100644 --- a/apps/remix/app/routes/embed+/v2+/authoring+/_layout.tsx +++ b/apps/remix/app/routes/embed+/v2+/authoring+/_layout.tsx @@ -1,5 +1,6 @@ import { PAID_PLAN_LIMITS } from '@documenso/ee/server-only/limits/constants'; import { LimitsProvider } from '@documenso/ee/server-only/limits/provider/client'; +import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics'; import { OrganisationProvider } from '@documenso/lib/client-only/providers/organisation'; import { APP_I18N_OPTIONS } from '@documenso/lib/constants/i18n'; import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token'; @@ -12,7 +13,7 @@ import type { OrganisationSession } from '@documenso/trpc/server/organisation-ro import { Spinner } from '@documenso/ui/primitives/spinner'; import { Trans } from '@lingui/react/macro'; import { OrganisationMemberRole, OrganisationType, TeamMemberRole } from '@prisma/client'; -import { useLayoutEffect, useState } from 'react'; +import { useEffect, useLayoutEffect, useState } from 'react'; import { isRouteErrorResponse, Outlet, useLoaderData } from 'react-router'; import { match } from 'ts-pattern'; @@ -166,8 +167,17 @@ export default function AuthoringLayout() { } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + const analytics = useAnalytics(); + const errorCode = isRouteErrorResponse(error) ? error.status : 500; + useEffect(() => { + analytics.captureException(error, { + source: 'embed', + location: 'embed_authoring_boundary', + }); + }, [error]); + return (
{match(errorCode) diff --git a/apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx b/apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx index bd000b8a8..2213ae56b 100644 --- a/apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx +++ b/apps/remix/app/routes/embed+/v2+/authoring+/envelope.create._index.tsx @@ -1,5 +1,6 @@ import { EnvelopeEditorProvider } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import type { SupportedLanguageCodes } from '@documenso/lib/constants/i18n'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token'; import { getTeamSettings } from '@documenso/lib/server-only/team/get-team-settings'; import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients'; @@ -10,6 +11,7 @@ import { ZEmbedCreateEnvelopeAuthoringSchema, } from '@documenso/lib/types/envelope-editor'; import type { TEnvelopeFieldAndMeta } from '@documenso/lib/types/field-meta'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { extractDerivedDocumentMeta } from '@documenso/lib/utils/document'; import { buildEmbeddedEditorOptions, buildEmbeddedFeatures } from '@documenso/lib/utils/embed-config'; import { prisma } from '@documenso/prisma'; @@ -76,6 +78,30 @@ export const loader = async ({ request }: Route.LoaderArgs) => { }, }); + fireAndForget(async () => { + const team = result.teamId + ? await prisma.team.findFirst({ + where: { + id: result.teamId, + }, + select: { + organisationId: true, + }, + }) + : null; + + captureServerEvent({ + event: 'App: Embed Session Started', + userId: result.userId, + organisationId: team?.organisationId, + teamId: result.teamId ?? undefined, + properties: { + type: 'authoring', + version: 'v2', + }, + }); + }); + return superLoaderJson({ token, tokenUserId: result.userId, diff --git a/apps/remix/app/routes/embed+/v2+/authoring+/envelope.edit.$id.tsx b/apps/remix/app/routes/embed+/v2+/authoring+/envelope.edit.$id.tsx index 155f5f96c..b35c08b0c 100644 --- a/apps/remix/app/routes/embed+/v2+/authoring+/envelope.edit.$id.tsx +++ b/apps/remix/app/routes/embed+/v2+/authoring+/envelope.edit.$id.tsx @@ -1,5 +1,6 @@ import { EnvelopeEditorProvider } from '@documenso/lib/client-only/providers/envelope-editor-provider'; import type { SupportedLanguageCodes } from '@documenso/lib/constants/i18n'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token'; import { getEditorEnvelopeById } from '@documenso/lib/server-only/envelope/get-editor-envelope-by-id'; import { getTeamSettings } from '@documenso/lib/server-only/team/get-team-settings'; @@ -94,6 +95,18 @@ export const loader = async ({ request, params }: Route.LoaderArgs) => { brandingLogo = settings.brandingLogo; } + captureServerEvent({ + event: 'App: Embed Session Started', + userId: result.userId, + organisationId: envelope.team.organisationId, + teamId: result.teamId ?? undefined, + properties: { + type: 'authoring', + version: 'v2', + envelopeId: envelope.id, + }, + }); + return superLoaderJson({ token, envelope, diff --git a/packages/lib/client-only/hooks/use-analytics.ts b/packages/lib/client-only/hooks/use-analytics.ts index ce302f7df..7d8953393 100644 --- a/packages/lib/client-only/hooks/use-analytics.ts +++ b/packages/lib/client-only/hooks/use-analytics.ts @@ -31,18 +31,21 @@ export function useAnalytics() { }; /** - * Capture an analytic event. + * Capture an exception event. * * @param error The error to capture. - * @param properties Properties to attach to the event. + * @param properties Properties to attach to the event, such as `source`, `location`, + * `recipientId` or `envelopeId`. Never attach recipient tokens. */ - const captureException = (error: Error, properties?: Record) => { + const captureException = (error: unknown, properties?: Record) => { if (!isPostHogEnabled) { return; } + const errorToCapture = error instanceof Error ? error : new Error(String(error)); + void getPosthog().then(({ default: posthog }) => { - posthog.captureException(error, properties); + posthog.captureException(errorToCapture, properties); }); }; diff --git a/packages/lib/client-only/providers/envelope-editor-provider.tsx b/packages/lib/client-only/providers/envelope-editor-provider.tsx index ea49f638c..70e929dbe 100644 --- a/packages/lib/client-only/providers/envelope-editor-provider.tsx +++ b/packages/lib/client-only/providers/envelope-editor-provider.tsx @@ -20,6 +20,7 @@ import { useSearchParams } from 'react-router'; import type { TDocumentEmailSettings } from '../../types/document-email'; import { formatDocumentsPath, formatTemplatesPath } from '../../utils/teams'; +import { useAnalytics } from '../hooks/use-analytics'; import type { TLocalField } from '../hooks/use-editor-fields'; import { useEditorFields } from '../hooks/use-editor-fields'; import { useEditorRecipients } from '../hooks/use-editor-recipients'; @@ -104,6 +105,7 @@ export const EnvelopeEditorProvider = ({ }: EnvelopeEditorProviderProps) => { const { t } = useLingui(); const { toast } = useToast(); + const analytics = useAnalytics(); const [_searchParams, setSearchParams] = useSearchParams(); @@ -241,6 +243,12 @@ export const EnvelopeEditorProvider = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: isEmbedded ? 'embed' : 'editor', + location: 'autosave_recipients', + envelopeId: envelope.id, + }); + setAutosaveError(true); toast({ @@ -304,6 +312,12 @@ export const EnvelopeEditorProvider = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: isEmbedded ? 'embed' : 'editor', + location: 'autosave_fields', + envelopeId: envelope.id, + }); + setAutosaveError(true); toast({ @@ -359,6 +373,12 @@ export const EnvelopeEditorProvider = ({ } catch (err) { console.error(err); + analytics.captureException(err, { + source: isEmbedded ? 'embed' : 'editor', + location: 'autosave_meta', + envelopeId: envelope.id, + }); + setAutosaveError(true); toast({ diff --git a/packages/lib/server-only/analytics/capture-server-event.ts b/packages/lib/server-only/analytics/capture-server-event.ts new file mode 100644 index 000000000..ba04ba96a --- /dev/null +++ b/packages/lib/server-only/analytics/capture-server-event.ts @@ -0,0 +1,83 @@ +import crypto from 'node:crypto'; +import { PostHog } from 'posthog-node'; + +import { env } from '../../utils/env'; + +/** + * Server-side product analytics client. + * + * Uses the same PostHog project as the client-side integration + * (NEXT_PUBLIC_POSTHOG_KEY). Not to be confused with the self-hoster + * telemetry client which reports to a separate project. + * + * Events are sent directly to PostHog rather than through the `/ingest` + * reverse proxy used by the browser. + */ +const POSTHOG_HOST = 'https://eu.i.posthog.com'; + +let client: PostHog | null | undefined; + +const getAnalyticsClient = () => { + if (client !== undefined) { + return client; + } + + const apiKey = env('NEXT_PUBLIC_POSTHOG_KEY'); + + // Low volume events, flush immediately so nothing is lost on shutdown. + client = apiKey ? new PostHog(apiKey, { host: POSTHOG_HOST, flushAt: 1 }) : null; + + return client; +}; + +type CaptureServerEventOptions = { + event: string; + + /** + * The authenticated user this event belongs to, if any. + * + * Used as the distinct ID so server events line up with client-side + * identified users. Anonymous events (e.g. embed signer sessions) get a + * random distinct ID instead. + */ + userId?: number; + organisationId?: string; + teamId?: number; + properties?: Record; +}; + +/** + * Capture a product analytics event from the server. + * + * No-ops when NEXT_PUBLIC_POSTHOG_KEY is not configured. Events are captured + * as anonymous events (no person profile processing) to keep usage costs low, + * cross-referencing is done via the `userId`, `organisationId` and `teamId` + * event properties. + * + * Never pass recipient tokens or document contents as properties. + */ +export const captureServerEvent = ({ + event, + userId, + organisationId, + teamId, + properties = {}, +}: CaptureServerEventOptions) => { + const posthog = getAnalyticsClient(); + + if (!posthog) { + return; + } + + posthog.capture({ + distinctId: userId ? String(userId) : `anon_${crypto.randomUUID()}`, + event, + properties: { + ...properties, + userId, + organisationId, + teamId, + $process_person_profile: false, + }, + }); +}; diff --git a/packages/lib/universal/fire-and-forget.ts b/packages/lib/universal/fire-and-forget.ts new file mode 100644 index 000000000..cdc46839b --- /dev/null +++ b/packages/lib/universal/fire-and-forget.ts @@ -0,0 +1,14 @@ +/** + * Run a function without awaiting it or letting it affect the caller. + * + * Both synchronous throws and promise rejections are swallowed, making this + * safe to call from request handlers and loaders for side work such as + * analytics that must never block or fail the response. + */ +export const fireAndForget = (fn: () => unknown) => { + try { + void Promise.resolve(fn()).catch(() => null); + } catch { + // Swallow synchronous errors. + } +}; diff --git a/packages/trpc/server/api-token-router/create-api-token.ts b/packages/trpc/server/api-token-router/create-api-token.ts index a01389f48..b48322478 100644 --- a/packages/trpc/server/api-token-router/create-api-token.ts +++ b/packages/trpc/server/api-token-router/create-api-token.ts @@ -1,4 +1,7 @@ +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { createApiToken } from '@documenso/lib/server-only/public-api/create-api-token'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; +import { prisma } from '@documenso/prisma'; import { authenticatedProcedure } from '../trpc'; import { ZCreateApiTokenRequestSchema, ZCreateApiTokenResponseSchema } from './create-api-token.types'; @@ -15,10 +18,26 @@ export const createApiTokenRoute = authenticatedProcedure }, }); - return await createApiToken({ + const createdToken = await createApiToken({ userId: ctx.user.id, teamId, tokenName, expiresIn: expirationDate, }); + + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { id: teamId }, + select: { organisationId: true }, + }); + + captureServerEvent({ + event: 'App: API Token Created', + userId: ctx.user.id, + teamId, + organisationId: team?.organisationId, + }); + }); + + return createdToken; }); diff --git a/packages/trpc/server/template-router/router.ts b/packages/trpc/server/template-router/router.ts index 99d4de784..e11e1f25d 100644 --- a/packages/trpc/server/template-router/router.ts +++ b/packages/trpc/server/template-router/router.ts @@ -1,6 +1,7 @@ import { getServerLimits } from '@documenso/ee/server-only/limits/server'; import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; import { jobs } from '@documenso/lib/jobs/client'; +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { getDocumentWithDetailsById } from '@documenso/lib/server-only/document/get-document-with-details-by-id'; import { sendDocument } from '@documenso/lib/server-only/document/send-document'; import { convertToPdf } from '@documenso/lib/server-only/document-conversion'; @@ -21,12 +22,14 @@ import { findTemplates } from '@documenso/lib/server-only/template/find-template import { getOrganisationTemplateById } from '@documenso/lib/server-only/template/get-organisation-template-by-id'; import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id'; import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { putNormalizedPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server'; import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions'; import { mapSecondaryIdToTemplateId } from '@documenso/lib/utils/envelope'; import { mapFieldToLegacyField } from '@documenso/lib/utils/fields'; import { mapRecipientToLegacyRecipient } from '@documenso/lib/utils/recipients'; import { mapEnvelopeToTemplateLite } from '@documenso/lib/utils/templates'; +import { prisma } from '@documenso/prisma'; import type { Envelope } from '@prisma/client'; import { DocumentDataType, EnvelopeType } from '@prisma/client'; @@ -744,7 +747,7 @@ export const templateRouter = router({ }); } - return await createTemplateDirectLink({ + const directLink = await createTemplateDirectLink({ userId, teamId, id: { @@ -753,6 +756,25 @@ export const templateRouter = router({ }, directRecipientId, }); + + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { id: template.teamId }, + select: { organisationId: true }, + }); + + captureServerEvent({ + event: 'App: Template Direct Link Enabled', + userId, + teamId: template.teamId, + organisationId: team?.organisationId, + properties: { + envelopeId: template.envelopeId, + }, + }); + }); + + return directLink; }), /** diff --git a/packages/trpc/server/webhook-router/router.ts b/packages/trpc/server/webhook-router/router.ts index 47fd237b4..423a39e1b 100644 --- a/packages/trpc/server/webhook-router/router.ts +++ b/packages/trpc/server/webhook-router/router.ts @@ -1,9 +1,12 @@ +import { captureServerEvent } from '@documenso/lib/server-only/analytics/capture-server-event'; import { createWebhook } from '@documenso/lib/server-only/webhooks/create-webhook'; import { deleteWebhookById } from '@documenso/lib/server-only/webhooks/delete-webhook-by-id'; import { editWebhook } from '@documenso/lib/server-only/webhooks/edit-webhook'; import { getWebhookById } from '@documenso/lib/server-only/webhooks/get-webhook-by-id'; import { getWebhooksByTeamId } from '@documenso/lib/server-only/webhooks/get-webhooks-by-team-id'; import { triggerTestWebhook } from '@documenso/lib/server-only/webhooks/trigger-test-webhook'; +import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; +import { prisma } from '@documenso/prisma'; import { authenticatedProcedure, router } from '../trpc'; import { findWebhookCallsRoute } from './find-webhook-calls'; @@ -51,7 +54,7 @@ export const webhookRouter = router({ createWebhook: authenticatedProcedure.input(ZCreateWebhookRequestSchema).mutation(async ({ input, ctx }) => { const { enabled, eventTriggers, secret, webhookUrl } = input; - return await createWebhook({ + const webhook = await createWebhook({ enabled, secret, webhookUrl, @@ -59,6 +62,25 @@ export const webhookRouter = router({ teamId: ctx.teamId, userId: ctx.user.id, }); + + fireAndForget(async () => { + const team = await prisma.team.findFirst({ + where: { id: ctx.teamId }, + select: { organisationId: true }, + }); + + captureServerEvent({ + event: 'App: Webhook Created', + userId: ctx.user.id, + teamId: ctx.teamId, + organisationId: team?.organisationId, + properties: { + triggerCount: eventTriggers.length, + }, + }); + }); + + return webhook; }), deleteWebhook: authenticatedProcedure.input(ZDeleteWebhookRequestSchema).mutation(async ({ input, ctx }) => { From 4285c88f126291cc87445f2f8ec6212d47927f6a Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Thu, 27 Aug 2026 11:25:37 +1000 Subject: [PATCH 23/64] chore: add provider request template (#3311) --- .../deploy-provider-request.yml | 61 +++++++++++++++++++ README.md | 44 ++++++++----- 2 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/deploy-provider-request.yml diff --git a/.github/ISSUE_TEMPLATE/deploy-provider-request.yml b/.github/ISSUE_TEMPLATE/deploy-provider-request.yml new file mode 100644 index 000000000..c59154391 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/deploy-provider-request.yml @@ -0,0 +1,61 @@ +name: 'One-Click Deploy Provider Request' +description: Request a new one-click deployment provider (Railway, Render, etc.) to be added to our README +title: 'One-Click Deploy Provider Request: [Provider Name]' +labels: ['deploy-provider-request'] +body: + - type: markdown + attributes: + value: | + Thanks for your interest in adding a one-click deploy option for Documenso! + + Each provider we list requires us to create, test, and maintain a deployment template, which is ongoing work on top of everything else. To keep this manageable, we ask that providers (or users) **open an issue instead of a PR** so the community can signal interest. + + **How this works:** + + - 👍 this issue if you'd like to see Documenso deployable on this provider. + - If community interest is high enough, we'll consider adding it to the README. + - Opening an issue is not a guarantee of inclusion. PRs adding badges without a prior issue and demonstrated interest will be closed. + - type: input + attributes: + label: Provider Name + placeholder: e.g. Railway + validations: + required: true + - type: input + attributes: + label: Provider Website + placeholder: e.g. https://railway.com + validations: + required: true + - type: input + attributes: + label: Deploy/Template URL + description: A link to an existing deployment template or deploy button URL, if one exists. + - type: dropdown + attributes: + label: Who creates and maintains the deployment template? + options: + - The provider + - Me / the community + - Nobody yet + validations: + required: true + - type: textarea + attributes: + label: Testing & Maintenance + description: Has the template been tested against the current Documenso release? How are updates handled when Documenso ships breaking changes (env vars, migrations, Docker changes)? + validations: + required: true + - type: textarea + attributes: + label: Why this provider? + description: Tell us why Documenso users would benefit — existing user base, region coverage, free tier, etc. + validations: + required: true + - type: checkboxes + attributes: + label: Please check the boxes that apply to this request. + options: + - label: I have searched existing issues to make sure this provider has not already been requested. + - label: I understand that inclusion depends on community interest and is not guaranteed. + - label: I understand that PRs adding deploy badges without a prior issue will be closed. diff --git a/README.md b/README.md index 642a285eb..a1ed84f30 100644 --- a/README.md +++ b/README.md @@ -186,21 +186,37 @@ For full instructions, requirements, and configuration details, see the [Self Ho ### One-Click Deploys -#### Railway +> [!NOTE] +> Want to see another provider listed here? Please [open a provider request](https://github.com/documenso/documenso/issues/new?template=deploy-provider-request.yml) instead of a PR so the community can signal interest. PRs adding deploy badges without a prior issue will be closed. -[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/deploy/DjrRRX?referralCode=EZR3s0&utm_medium=integration&utm_source=template&utm_campaign=generic) - -#### Render - -[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/documenso/documenso) - -#### Koyeb - -[![Deploy to Koyeb](https://www.koyeb.com/static/images/deploy/button.svg)](https://app.koyeb.com/deploy?type=git&repository=github.com/documenso/documenso&branch=main&name=documenso-app&builder=dockerfile&dockerfile=/docker/Dockerfile) - -#### Elestio - -[![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/documenso) + + + + + + + + + + + +
+ + Deploy on Railway + + + + Deploy to Render + + + + Deploy to Koyeb + +
+ + Deploy on Elestio + +
## Security From 5082b475a0b79ee94265d769455f398eae8a934b Mon Sep 17 00:00:00 2001 From: Konrad <11725227+mKoonrad@users.noreply.github.com> Date: Fri, 28 Aug 2026 09:08:53 +0200 Subject: [PATCH 24/64] chore: update Polish translation (#3316) --- packages/lib/translations/pl/web.po | 161 +++++++++++++++++----------- 1 file changed, 99 insertions(+), 62 deletions(-) diff --git a/packages/lib/translations/pl/web.po b/packages/lib/translations/pl/web.po index f9eeddd0d..207cae377 100644 --- a/packages/lib/translations/pl/web.po +++ b/packages/lib/translations/pl/web.po @@ -8,7 +8,7 @@ msgstr "" "Language: pl\n" "Project-Id-Version: documenso-app\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-08-13 14:22\n" +"PO-Revision-Date: 2026-08-27 12:58\n" "Last-Translator: \n" "Language-Team: Polish\n" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" @@ -316,7 +316,7 @@ msgstr "Sprawdź i {recipientActionVerb} dokument „{1}” utworzony przez zesp #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "{0} has invited you to sign this document." -msgstr "" +msgstr "Organizacja {0} zaprosiła Cię do podpisania dokumentu." #. placeholder {0}: team.name #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts @@ -442,7 +442,7 @@ msgstr "Sprawdź i {action} dokument „{documentName}” utworzony przez użytk #: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx msgid "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {You can download up to # document at a time. Deselect some documents to continue.} other {You can download up to # documents at a time. Deselect some documents to continue.}}" -msgstr "" +msgstr "{MAX_BULK_DOWNLOAD_ENVELOPES, plural, one {Możesz pobrać jednocześnie # dokument. Odznacz niektóre dokumenty.} few {Możesz pobrać jednocześnie # dokumenty. Odznacz niektóre dokumenty.} many {Możesz pobrać jednocześnie # dokumentów. Odznacz niektóre dokumenty.} other {Możesz pobrać jednocześnie # dokumentów. Odznacz niektóre dokumenty.}}" #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "{MAXIMUM_PASSKEYS, plural, one {You cannot have more than # passkey.} other {You cannot have more than # passkeys.}}" @@ -525,11 +525,11 @@ msgstr "Sprawdź i {action} dokument „{documentName}” utworzony przez zespó #: apps/remix/app/components/general/app-command-menu.tsx msgid "{totalVisibleCount, plural, one {# item} other {# items}}" -msgstr "" +msgstr "{totalVisibleCount, plural, one {# element} few {# elementy} many {# elementów} other {# elementów}}" #: apps/remix/app/components/general/app-command-menu.tsx msgid "{totalVisibleCount, plural, one {# result} other {# results}}" -msgstr "" +msgstr "{totalVisibleCount, plural, one {# wynik} few {# wyniki} many {# wyników} other {# wyników}}" #: packages/lib/utils/document-audit-logs.ts msgid "{user} added a field" @@ -1237,7 +1237,7 @@ msgstr "Konto zostało rozłączone" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Accounts are automatically added to your organisation on sign-in" -msgstr "" +msgstr "Automatyczne dodawanie kont do organizacji podczas logowania" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" @@ -2455,7 +2455,7 @@ msgstr "Obramowanie" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Border radius" -msgstr "Zaokrąglenia obramowania" +msgstr "Zaokrąglenie obramowania" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Border Radius" @@ -2471,7 +2471,7 @@ msgstr "Dół" #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Brand accent" -msgstr "" +msgstr "Kolor marki" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" @@ -2479,7 +2479,7 @@ msgstr "Kolory marki" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Brand colours, including background, foreground, primary, and border colours" -msgstr "Kolorów marki, w tym kolorów tła, przycisków i obramowań" +msgstr "Kolory marki, w tym kolory tła, przycisków i obramowań" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Details" @@ -2491,7 +2491,7 @@ msgstr "Strona internetowa marki" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Brand website and brand details" -msgstr "Strony internetowej i szczegółów marki" +msgstr "Strona internetowa i szczegóły marki" #: apps/remix/app/components/general/admin-global-settings-section.tsx #: packages/lib/utils/settings-nav.ts @@ -2581,7 +2581,7 @@ msgstr "Akceptując prośbę, umożliwisz zespołowi <0>{teamName}:" #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "By deleting this document, the following will occur:" -msgstr "Usunięcie dokumentu spowoduje następujące skutki:" +msgstr "Po usunięciu dokumentu:" #: apps/remix/app/components/general/document-signing/document-signing-auth-2fa.tsx msgid "By enabling 2FA, you will be required to enter a code from your authenticator app every time you sign in using email password." @@ -3008,11 +3008,11 @@ msgstr "Komunikacja" #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Company details" -msgstr "" +msgstr "Szczegóły firmy" #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Company details and website in email footers" -msgstr "" +msgstr "Szczegóły firmy i strona internetowa w stopkach" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Compare all plans and features in detail" @@ -3203,7 +3203,7 @@ msgstr "Informacje kontaktowe" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Contact Sales" -msgstr "" +msgstr "Skontaktuj się z działem sprzedaży" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Contact sales here" @@ -3215,7 +3215,7 @@ msgstr "Skontaktuj się z nami" #: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx msgid "Contact your organisation owner to upgrade plans." -msgstr "" +msgstr "Skontaktuj się z właścicielem organizacji, aby zaktualizować plan." #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" @@ -3271,7 +3271,7 @@ msgstr "Przejdź do logowania" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Continue with SSO" -msgstr "" +msgstr "Logowanie SSO" #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Controls how long recipients have to complete signing before the document expires. After expiration, recipients can no longer sign the document." @@ -3718,11 +3718,11 @@ msgstr "Niestandardowy plik {0} MB" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Custom branding enabled setting" -msgstr "Niestandardowych ustawień marki" +msgstr "Niestandardowe ustawienia marki" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Custom CSS" -msgstr "Niestandardowego CSS" +msgstr "Niestandardowy CSS" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Custom CSS is sanitised on save. Layout-breaking properties, remote URLs, and pseudo-elements are stripped automatically. Any rules dropped during sanitisation will be shown after you save." @@ -4376,7 +4376,7 @@ msgstr "Wszystkie dokumenty" #: apps/remix/app/utils/toast-error-messages.ts msgid "Document already completed" -msgstr "" +msgstr "Dokument został już zakończony" #: apps/remix/app/components/general/envelope-signing/envelope-signing-complete-dialog.tsx msgid "Document already signed" @@ -4565,7 +4565,7 @@ msgstr "Przeniesiono dokument do zespołu" #: apps/remix/app/utils/toast-error-messages.ts msgid "Document no longer available" -msgstr "" +msgstr "Dokument nie jest już dostępny" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Document no longer available to sign" @@ -4573,7 +4573,7 @@ msgstr "Dokument nie jest już dostępny do podpisania" #: apps/remix/app/utils/toast-error-messages.ts msgid "Document not ready" -msgstr "" +msgstr "Dokument nie jest gotowy" #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" @@ -5033,7 +5033,7 @@ msgstr "np. Resend (plan darmowy)" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Easy DNS setup with auto-generated DKIM and SPF records" -msgstr "" +msgstr "Łatwa konfiguracja DNS z automatycznie generowanymi rekordami DKIM i SPF" #: apps/remix/app/components/general/document/document-page-view-button.tsx #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx @@ -5709,7 +5709,7 @@ msgstr "Wystąpił błąd podczas przesyłania pliku" #: apps/remix/app/components/general/app-command-menu.tsx msgid "esc" -msgstr "escape" +msgstr "esc" #: apps/remix/app/components/general/webhook-logs-sheet.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx @@ -6202,7 +6202,7 @@ msgstr "Niemiecki" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Give your members a dedicated single sign-on portal. The SSO portal is available on the Enterprise plan." -msgstr "" +msgstr "Zapewnij swoim użytkownikom logowanie SSO. Funkcja dostępna w planie Enterprise." #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/app-command-menu.tsx @@ -6438,7 +6438,7 @@ msgstr "Ukryj" #: packages/ui/components/document/envelope-recipient-field-tooltip.tsx msgid "Hide field" -msgstr "" +msgstr "Ukryj pole" #: apps/remix/app/components/general/admin-license-card.tsx msgid "Hide license key" @@ -6852,7 +6852,7 @@ msgstr "To nie jest Twoja kolej na podpisanie dokumentu. Gdy nadejdzie Twoja kol #: apps/remix/app/utils/toast-error-messages.ts msgid "It's not your turn to sign yet" -msgstr "" +msgstr "To nie jest Twoja kolej na podpisanie dokumentu" #: packages/lib/constants/i18n.ts msgid "Italian" @@ -6974,7 +6974,7 @@ msgstr "Użyto" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Last Used" -msgstr "" +msgstr "Użyto" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx @@ -7603,7 +7603,7 @@ msgstr "Ustawienia nazwy" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Named senders with defaults per team, template or document" -msgstr "" +msgstr "Zdefiniowani nadawcy z domyślnymi ustawieniami dla zespołu, szablonu lub dokumentu" #: apps/remix/app/components/general/app-command-menu.tsx msgid "Navigate" @@ -7990,14 +7990,14 @@ msgstr "Na tej stronie możesz utworzyć nowe webhooki i zarządzać obecnymi." #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx #: apps/remix/app/components/dialogs/document-preferences-reset-dialog.tsx msgid "Once confirmed, the following will be reset:" -msgstr "Potwierdzenie akcji spowoduje zresetowanie:" +msgstr "Po potwierdzeniu zresetowane zostaną:" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-delete-dialog.tsx msgid "Once confirmed, the following will occur:" -msgstr "Potwierdzenie akcji spowoduje następujące skutki:" +msgstr "Po potwierdzeniu:" #: packages/lib/constants/template.ts 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." @@ -8021,7 +8021,7 @@ msgstr "Jeden z dokumentów ma niezgodną rolę w procesie podpisywania." #: apps/remix/app/utils/toast-error-messages.ts msgid "One or more of your required fields have not been saved. Please refresh the page, complete any empty required fields, and try again." -msgstr "" +msgstr "Co najmniej jedno z wymaganych pól nie zostało zapisane. Odśwież stronę, uzupełnij wymagane pola i spróbuj ponownie." #: apps/remix/app/components/forms/document-preferences-form.tsx msgid "Only admins can access and view the document" @@ -8756,7 +8756,7 @@ msgstr "Wybierz, w jaki sposób chcesz otrzymać swój kod weryfikacyjny." #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Please sign: Example.pdf" -msgstr "" +msgstr "Podpisz dokument: umowa.pdf" #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Please try a different domain." @@ -8789,6 +8789,10 @@ msgstr "Prześlij dokument, aby kontynuować" msgid "Please upload a logo" msgstr "Prześlij logo" +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "Please upload a valid image file." +msgstr "Prześlij prawidłową grafikę." + #: packages/lib/constants/i18n.ts msgid "Polish" msgstr "Polski" @@ -8946,7 +8950,7 @@ msgstr "Szablony publiczne są powiązane z Twoim profilem publicznym. Wszelkie #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Put your own brand on every document you send. Branding is available on the Teams plan and above." -msgstr "" +msgstr "Umieść swoje logo na każdym wysyłanym dokumencie. Branding jest dostępny w planie Teams i wyższym." #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Quick Actions" @@ -9278,7 +9282,7 @@ msgstr "Przekierowywanie do {0}..." #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Redirecting to your identity provider" -msgstr "" +msgstr "Przekierowywanie do dostawcy tożsamości" #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx @@ -9650,7 +9654,7 @@ msgstr "Zapewniamy, że Twój dokument jest poufny i nigdy nie zostanie udostęp #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Restrict sign-ins by email domain and choose the default role" -msgstr "" +msgstr "Ogranicz logowanie do wybranych domen i przypisz domyślną rolę" #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "Restricted Access" @@ -9814,7 +9818,7 @@ msgstr "Szukaj identyfikatora lub nazwy" #: apps/remix/app/routes/_authenticated+/admin+/documents._index.tsx msgid "Search by document title, recipient:123, team:123 or user:123" -msgstr "" +msgstr "Szukaj tytułu dokumentu, odbiorcy, zespołu lub użytkownika" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" @@ -10112,7 +10116,7 @@ msgstr "Wybierz widoczność" #: apps/remix/app/components/tables/envelopes-table-bulk-action-bar.tsx msgid "selected" -msgstr "" +msgstr "zaznaczono" #: apps/remix/app/components/dialogs/envelopes-bulk-delete-dialog.tsx msgid "Selected documents will be permanently deleted" @@ -10170,7 +10174,7 @@ msgstr "Wyślij dokument" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Send documents from your own domain. Email domains are available on the Enterprise plan." -msgstr "" +msgstr "Wysyłaj dokumenty ze swojej domeny. Domeny są dostępne w planie Enterprise." #: packages/email/templates/confirm-team-email.tsx msgid "Send documents on behalf of the team using the email address" @@ -10182,7 +10186,7 @@ msgstr "Wyślij dokumenty do odbiorców natychmiast" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Send emails to recipients from your domain" -msgstr "" +msgstr "Wysyłaj wiadomości ze swojej domeny" #: apps/remix/app/components/general/envelope-editor/envelope-editor.tsx msgid "Send Envelope" @@ -10232,11 +10236,11 @@ msgstr "Nadawca został zgłoszony" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Sending from app.documenso.com" -msgstr "" +msgstr "Wysyłanie z app.documenso.com" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Sending from your domain" -msgstr "" +msgstr "Wysyłanie z Twojej domeny" #: apps/remix/app/components/forms/forgot-password.tsx msgid "Sending Reset Email..." @@ -10260,7 +10264,7 @@ msgstr "Wysłano w tym okresie" #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Separate branding per team" -msgstr "" +msgstr "Oddzielny branding dla zespołów" #: apps/remix/app/routes/_authenticated+/settings+/security.sessions.tsx msgid "Session revoked" @@ -10501,6 +10505,7 @@ msgid "Signature ID" msgstr "Identyfikator podpisu" #: packages/ui/primitives/signature-pad/signature-pad-draw.tsx +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx msgid "Signature is too small" msgstr "Podpis jest zbyt mały" @@ -10541,7 +10546,7 @@ msgstr "Podpisany" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Signed in" -msgstr "" +msgstr "Zalogowano" #: apps/remix/app/components/general/envelope-signing/envelope-signer-header.tsx msgid "Signer" @@ -10609,7 +10614,7 @@ msgstr "Logowanie..." #: apps/remix/app/utils/toast-error-messages.ts msgid "Signing link expired" -msgstr "" +msgstr "Link do podpisywania wygasł" #: apps/remix/app/components/general/document/document-page-view-dropdown.tsx #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx @@ -10665,7 +10670,7 @@ msgstr "Od {0}" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Single sign-on" -msgstr "" +msgstr "Logowanie SSO" #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Site Banner" @@ -10688,7 +10693,7 @@ msgstr "Niektóre pola są umieszczone jedno nad drugim. Może to utrudnić podp #: apps/remix/app/utils/toast-error-messages.ts msgid "Some fields were not saved" -msgstr "" +msgstr "Niektóre pola nie zostały zapisane" #: apps/remix/app/components/general/app-command-menu.tsx msgid "Some searches failed — results may be incomplete." @@ -11605,7 +11610,7 @@ msgstr "Dokument został odrzucony w zewnętrznej usłudze w imieniu odbiorcy" #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "The document will be hidden from your account" -msgstr "Dokument zostanie ukryty w Twoim koncie" +msgstr "Dokument zostanie ukryty na Twoim koncie" #: apps/remix/app/components/dialogs/template-use-dialog.tsx msgid "The document will be immediately sent to recipients if this is checked." @@ -11697,6 +11702,14 @@ msgstr "Brak pola podpisu dla następujących podpisujących:" msgid "The following team has been deleted. You will no longer be able to access this team and its documents" msgstr "Następujący zespół został usunięty. Nie będziesz mógł już uzyskać dostępu do tego zespołu i jego dokumentów" +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "The image could not be loaded. Please try again." +msgstr "Nie można załadować grafiki. Spróbuj ponownie." + +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "The image must be smaller than 5MB." +msgstr "Maksymalny rozmiar grafiki to 5 MB." + #: apps/remix/app/components/general/admin-license-card.tsx msgid "The license key has been copied to your clipboard" msgstr "Klucz licencyjny został skopiowany do schowka" @@ -12027,7 +12040,7 @@ msgstr "Szablon bezpośredniego linku nie może zostać użyty, ponieważ co naj #: apps/remix/app/utils/toast-error-messages.ts msgid "This document can no longer be signed. It may have been removed by the sender, or your signing access may have been revoked. Please contact the sender for a new signing link." -msgstr "" +msgstr "Nie można podpisać dokumentu. Być może został on usunięty przez nadawcę lub Twoje uprawnienia do podpisywania zostały unieważnione. Skontaktuj się z nadawcą, aby uzyskać nowy link do podpisywania." #: packages/email/template-components/template-document-super-delete.tsx msgid "This document can not be recovered, if you would like to dispute the reason for future documents please contact support." @@ -12059,7 +12072,7 @@ msgstr "Nie można zapisać dokumentu jako szablonu. Spróbuj ponownie." #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has already been completed and no further signatures can be added." -msgstr "" +msgstr "Dokument został już zakończony i nie wymaga kolejnych podpisów." #: apps/remix/app/components/general/envelope-editor/envelope-recipient-selector.tsx #: packages/ui/primitives/recipient-selector.tsx @@ -12081,7 +12094,7 @@ msgstr "Dokument został anulowany przez właściciela." #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." -msgstr "" +msgstr "Dokument został anulowany przez nadawcę i nie można go już podpisać. Jeśli uważasz to za błąd, skontaktuj się z nadawcą." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" @@ -12089,7 +12102,7 @@ msgstr "Dokument został odrzucony przez odbiorcę" #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has been rejected by a recipient and can no longer be signed." -msgstr "" +msgstr "Dokument został odrzucony przez odbiorcę i nie można go już podpisać." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been signed by all recipients" @@ -12097,7 +12110,7 @@ msgstr "Dokument został podpisany przez wszystkich odbiorców" #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has not been sent for signing yet. Please wait for the sender to send it before signing." -msgstr "" +msgstr "Dokument nie został jeszcze wysłany do podpisania. Poczekaj na wysłanie go przez nadawcę." #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has too many recipients. Please remove some recipients or contact support if you need more." @@ -12113,7 +12126,7 @@ msgstr "Dokument jest szkicem i nie został wysłany" #: apps/remix/app/utils/toast-error-messages.ts msgid "This document is signed in a set order and other recipients must sign before you. You will receive an email when it is your turn." -msgstr "" +msgstr "Dokument jest podpisywany zgodnie z ustaloną kolejnością. Gdy nadejdzie Twoja kolej, otrzymasz wiadomość." #: apps/remix/app/components/general/legacy-field-warning-popover.tsx msgid "This document is using legacy field insertion, we recommend using the new field insertion method for more accurate results." @@ -12192,6 +12205,10 @@ msgstr "Typ pliku nie jest obsługiwany. Prześlij dokument PDF lub Word." msgid "This folder contains multiple items. Deleting it will remove all subfolders and move all nested documents and templates to the root folder." msgstr "Folder zawiera wiele elementów. Usunięcie go spowoduje przeniesienie wszystkich dokumentów i szablonów znajdujących się w tym folderze do folderu głównego." +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "This image is invalid, please upload a valid image file." +msgstr "Grafika jest nieprawidłowa. Prześlij prawidłowy plik." + #: apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx #: packages/ui/primitives/template-flow/add-template-settings.tsx msgid "This is how the document will reach the recipients once the document is ready for signing." @@ -12774,6 +12791,10 @@ msgstr "Nie można się zalogować" msgid "Unable to start the signing flow" msgstr "Nie można rozpocząć procesu podpisywania" +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "Unable to upload image" +msgstr "Nie można przesłać grafiki" + #: apps/remix/app/components/general/document-signing/document-signing-auth-2fa.tsx #: apps/remix/app/components/general/document-signing/document-signing-auth-passkey.tsx #: apps/remix/app/components/general/document-signing/document-signing-auth-password.tsx @@ -12788,6 +12809,7 @@ msgstr "Niezakończono" #: apps/remix/app/components/forms/form-sticky-save-bar.tsx #: packages/ui/primitives/signature-pad/signature-pad-draw.tsx +#: packages/ui/primitives/signature-pad/signature-pad-draw.tsx msgid "Undo" msgstr "Cofnij" @@ -12832,15 +12854,15 @@ msgstr "Rozłącz" #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Unlock Branding Preferences" -msgstr "" +msgstr "Odblokuj ustawienia brandingu" #: apps/remix/app/components/general/settings-upsell/email-domains-upsell.tsx msgid "Unlock Email Domains" -msgstr "" +msgstr "Odblokuj domeny" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Unlock the Organisation SSO Portal" -msgstr "" +msgstr "Odblokuj logowanie SSO organizacji" #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" @@ -13017,7 +13039,7 @@ msgstr "Ulepsz organizację <0>{0} do planu {planName}" #: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx msgid "Upgrade Plan" -msgstr "" +msgstr "Ulepsz plan" #: apps/remix/app/components/general/envelope/envelope-drop-zone-wrapper.tsx msgid "Upgrade your plan to upload more documents" @@ -13078,6 +13100,10 @@ msgstr "Prześlij dokumenty i dodaj odbiorców" msgid "Upload failed" msgstr "Przesyłanie nie powiodło się" +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "Upload New Image" +msgstr "Prześlij nową grafikę" + #: apps/remix/app/components/general/admin-global-settings-section.tsx msgid "Upload signature" msgstr "Podpis przesyłany" @@ -13506,7 +13532,7 @@ msgstr "Oczekiwanie na innych" #: packages/lib/jobs/definitions/emails/send-document-pending-email.handler.ts msgid "Waiting for others to complete signing" -msgstr "" +msgstr "Oczekiwanie na zakończenie podpisywania przez innych" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "Waiting for others to sign" @@ -14004,7 +14030,7 @@ msgstr "Witaj z powrotem! Oto podsumowanie Twojego konta." #. placeholder {0}: organisation.name #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Welcome to {0}" -msgstr "" +msgstr "Witaj w organizacji {0}" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "Welcome to {organisationName}" @@ -14085,7 +14111,7 @@ msgstr "W ramach limitu" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Works with any OIDC provider — Okta, Entra ID, Google and more" -msgstr "" +msgstr "Działa z dowolnym dostawcą OIDC: Okta, Entra ID, Google i więcej" #: apps/remix/app/components/forms/public-profile-form.tsx msgid "Write a description to display on your public profile" @@ -15102,7 +15128,7 @@ msgstr "Koperta została ponownie wysłana." #: apps/remix/app/components/general/settings-upsell/branding-upsell.tsx msgid "Your logo on signing pages and emails" -msgstr "" +msgstr "Twoje logo na stronach podpisywania i w wiadomościach" #: apps/remix/app/components/general/document-signing/document-signing-complete-dialog.tsx msgid "Your Name" @@ -15239,7 +15265,7 @@ msgstr "Certyfikat podpisu jest nieważny, wygasł lub brakuje w nim wymaganego #: apps/remix/app/utils/toast-error-messages.ts msgid "Your signing link has expired. Please contact the sender to request a new one." -msgstr "" +msgstr "Twój link do podpisywania wygasł. Skontaktuj się z nadawcą, aby otrzymać nowy link." #: packages/lib/utils/document-audit-logs.ts msgid "Your signing provider authentication failed" @@ -15322,3 +15348,14 @@ msgstr "Twój kod weryfikacyjny:" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "your-domain.com another-domain.com" msgstr "twoja-domena.pl inna-domena.pl" + +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "Zoom in" +msgstr "Powiększ" + +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +#: packages/ui/primitives/signature-pad/signature-pad-upload.tsx +msgid "Zoom out" +msgstr "Pomniejsz" + From eba71d9be494d9646a592f414770de34219f6398 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Tue, 1 Sep 2026 13:17:48 +1000 Subject: [PATCH 25/64] fix: prevent dialogs from closing on blur (#3314) --- .../e2e/templates/template-bulk-send.spec.ts | 80 +++++++++++++++++++ packages/ui/primitives/dropdown-menu.tsx | 13 +++ patches/@radix-ui+react-menu+2.1.24.patch | 44 ++++++++++ 3 files changed, 137 insertions(+) create mode 100644 packages/app-tests/e2e/templates/template-bulk-send.spec.ts create mode 100644 patches/@radix-ui+react-menu+2.1.24.patch diff --git a/packages/app-tests/e2e/templates/template-bulk-send.spec.ts b/packages/app-tests/e2e/templates/template-bulk-send.spec.ts new file mode 100644 index 000000000..70ec298ac --- /dev/null +++ b/packages/app-tests/e2e/templates/template-bulk-send.spec.ts @@ -0,0 +1,80 @@ +import { prisma } from '@documenso/prisma'; +import { seedTeam } from '@documenso/prisma/seed/teams'; +import { seedTemplate } from '@documenso/prisma/seed/templates'; +import { expect, test } from '@playwright/test'; +import { EnvelopeType } from '@prisma/client'; + +import { apiSignin } from '../fixtures/authentication'; +import { openDropdownMenu } from '../fixtures/generic'; + +test('[TEMPLATES]: bulk send via CSV from the table action dropdown', async ({ page }) => { + const { team, owner } = await seedTeam(); + + await seedTemplate({ + title: 'Bulk send template', + userId: owner.id, + teamId: team.id, + }); + + const uniqueRecipientEmail = `bulk-send-${Date.now()}@documenso.com`; + + await apiSignin({ + page, + email: owner.email, + redirectPath: `/t/${team.url}/templates`, + }); + + const actionBtn = page + .getByRole('row', { name: 'Bulk send template' }) + .getByRole('cell', { name: 'Use Template' }) + .getByRole('button') + .nth(1); + + await openDropdownMenu(page, actionBtn); + + await page.getByText('Bulk Send via CSV').click(); + + const dialog = page.getByRole('dialog').filter({ hasText: 'Bulk Send Template via CSV' }); + + await expect(dialog).toBeVisible(); + + // Opening the native file picker blurs the window. Radix dropdown menus close themselves on + // window blur, which used to unmount this dialog when it was nested inside the menu content, + // silently discarding the user's file selection. + await page.evaluate(() => window.dispatchEvent(new Event('blur'))); + + await expect(dialog).toBeVisible(); + + const csv = ['recipient_1_email,recipient_1_name', `${uniqueRecipientEmail},Bulk Recipient`].join('\n'); + + await dialog.locator('input[type="file"]').setInputFiles({ + name: 'bulk-send.csv', + mimeType: 'text/csv', + buffer: Buffer.from(csv), + }); + + await expect(dialog.getByText('bulk-send.csv')).toBeVisible(); + + await dialog.getByRole('button', { name: 'Upload and Process' }).click(); + + await expect(page.getByText('Your bulk send has been initiated').first()).toBeVisible(); + + // The bulk send runs as a background job, so poll for the created document. + await expect + .poll( + async () => + await prisma.envelope.count({ + where: { + type: EnvelopeType.DOCUMENT, + teamId: team.id, + recipients: { + some: { + email: uniqueRecipientEmail, + }, + }, + }, + }), + { timeout: 30_000 }, + ) + .toBe(1); +}); diff --git a/packages/ui/primitives/dropdown-menu.tsx b/packages/ui/primitives/dropdown-menu.tsx index 98109c460..9c5bdd16e 100644 --- a/packages/ui/primitives/dropdown-menu.tsx +++ b/packages/ui/primitives/dropdown-menu.tsx @@ -4,6 +4,19 @@ import * as React from 'react'; import { cn } from '../lib/utils'; +/** + * Note: The underlying @radix-ui/react-menu package is patched, see + * patches/@radix-ui+react-menu+2.1.24.patch. + * + * Since @radix-ui/react-menu 2.1.18, Radix closes any open menu when the window fires a + * "blur" event. Opening a native file picker blurs the window, which would close the + * menu and unmount anything rendered within its content, such as dialogs containing + * file inputs, silently discarding the user's file selection. The patch removes that + * behaviour since there is currently no native prop to opt out of it, see + * https://github.com/radix-ui/primitives/issues/3618. + * + * Regression test: packages/app-tests/e2e/templates/template-bulk-send.spec.ts + */ const DropdownMenu = DropdownMenuPrimitive.Root; const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; diff --git a/patches/@radix-ui+react-menu+2.1.24.patch b/patches/@radix-ui+react-menu+2.1.24.patch new file mode 100644 index 000000000..4b5dfe850 --- /dev/null +++ b/patches/@radix-ui+react-menu+2.1.24.patch @@ -0,0 +1,44 @@ +diff --git a/node_modules/@radix-ui/react-menu/dist/index.js b/node_modules/@radix-ui/react-menu/dist/index.js +index b3f6113..d8ec2e3 100644 +--- a/node_modules/@radix-ui/react-menu/dist/index.js ++++ b/node_modules/@radix-ui/react-menu/dist/index.js +@@ -139,9 +139,14 @@ var Menu = /* @__PURE__ */ __name((props) => { + if (!open) { + return; + } +- const handleBlur = /* @__PURE__ */ __name(() => handleOpenChange(false), "handleBlur"); +- window.addEventListener("blur", handleBlur); +- return () => window.removeEventListener("blur", handleBlur); ++ // DOCUMENSO PATCH: @radix-ui/react-menu 2.1.18+ closes open menus when the window ++ // fires a "blur" event. Opening a native file picker blurs the window, which closes ++ // the menu and unmounts anything rendered within its content, such as dialogs that ++ // contain file inputs, silently discarding the user's file selection. This restores ++ // the pre-2.1.18 behaviour. Regression test: e2e/templates/template-bulk-send.spec.ts ++ // const handleBlur = () => handleOpenChange(false); ++ // window.addEventListener("blur", handleBlur); ++ // return () => window.removeEventListener("blur", handleBlur); + }, [open, handleOpenChange]); + return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)( + MenuProvider, +diff --git a/node_modules/@radix-ui/react-menu/dist/index.mjs b/node_modules/@radix-ui/react-menu/dist/index.mjs +index cd4303a..68865e3 100644 +--- a/node_modules/@radix-ui/react-menu/dist/index.mjs ++++ b/node_modules/@radix-ui/react-menu/dist/index.mjs +@@ -73,9 +73,14 @@ var Menu = /* @__PURE__ */ __name((props) => { + if (!open) { + return; + } +- const handleBlur = /* @__PURE__ */ __name(() => handleOpenChange(false), "handleBlur"); +- window.addEventListener("blur", handleBlur); +- return () => window.removeEventListener("blur", handleBlur); ++ // DOCUMENSO PATCH: @radix-ui/react-menu 2.1.18+ closes open menus when the window ++ // fires a "blur" event. Opening a native file picker blurs the window, which closes ++ // the menu and unmounts anything rendered within its content, such as dialogs that ++ // contain file inputs, silently discarding the user's file selection. This restores ++ // the pre-2.1.18 behaviour. Regression test: e2e/templates/template-bulk-send.spec.ts ++ // const handleBlur = () => handleOpenChange(false); ++ // window.addEventListener("blur", handleBlur); ++ // return () => window.removeEventListener("blur", handleBlur); + }, [open, handleOpenChange]); + return /* @__PURE__ */ jsx(PopperPrimitive.Root, { ...popperScope, children: /* @__PURE__ */ jsx( + MenuProvider, From 937e9376d84d701e9a6540857b3b23d2901938fc Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Tue, 1 Sep 2026 06:54:20 +0300 Subject: [PATCH 26/64] fix: enlarge envelope field resize handle hit area (#3315) --- .../envelope-editor-fields-page-renderer.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx index c9deb51ad..e82232311 100644 --- a/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx +++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-fields-page-renderer.tsx @@ -38,6 +38,9 @@ import { useEffect, useMemo, useRef, useState } from 'react'; import { fieldButtonList } from './envelope-editor-fields-drag-drop'; import { EnvelopeRecipientSelectorCommand } from './envelope-recipient-selector'; +/** How far past a resize handle you can still grab it, in screen pixels. */ +const TRANSFORMER_ANCHOR_HIT_STROKE_PX = 24; + export const EnvelopeEditorFieldsPageRenderer = ({ pageData }: { pageData: PageRenderData }) => { const { t, i18n } = useLingui(); const analytics = useAnalytics(); @@ -359,6 +362,9 @@ export const EnvelopeEditorFieldsPageRenderer = ({ pageData }: { pageData: PageR shouldOverdrawWholeArea: true, ignoreStroke: true, flipEnabled: false, + anchorStyleFunc: (anchor) => { + anchor.hitStrokeWidth(TRANSFORMER_ANCHOR_HIT_STROKE_PX / scale); + }, boundBoxFunc: (oldBox, newBox) => { // Enforce minimum size if (newBox.width < 30 || newBox.height < 20) { From a2745ed3c2cc6d4a1b5c1055769a32843019adb1 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Tue, 1 Sep 2026 06:54:57 +0300 Subject: [PATCH 27/64] docs: clarify team API token and certificate behavior (#3317) --- apps/docs/content/docs/developers/api/teams.mdx | 10 +++++----- .../docs/self-hosting/deployment/docker.mdx | 16 +++++++++++++++- .../users/organisations/preferences/document.mdx | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/docs/content/docs/developers/api/teams.mdx b/apps/docs/content/docs/developers/api/teams.mdx index 99d708b41..0d869c56c 100644 --- a/apps/docs/content/docs/developers/api/teams.mdx +++ b/apps/docs/content/docs/developers/api/teams.mdx @@ -95,7 +95,7 @@ Documents created with a team token belong to that team: ```bash curl -X POST "https://app.documenso.com/api/v2/envelope/create" \ - -H "Authorization: api_team_xxxxxxxxxxxxxxxx" \ + -H "Authorization: api_xxxxxxxxxxxxxxxx" \ -H "Content-Type: multipart/form-data" \ -F 'payload={ "type": "DOCUMENT", @@ -157,11 +157,11 @@ Retrieve all documents belonging to the team: ```bash # List all team documents curl -X GET "https://app.documenso.com/api/v2/envelope" \ - -H "Authorization: api_team_xxxxxxxxxxxxxxxx" + -H "Authorization: api_xxxxxxxxxxxxxxxx" # Filter by status curl -X GET "https://app.documenso.com/api/v2/envelope?status=PENDING" \ - -H "Authorization: api_team_xxxxxxxxxxxxxxxx" + -H "Authorization: api_xxxxxxxxxxxxxxxx" ```` @@ -191,7 +191,7 @@ Templates created with a team token are shared across the team. ```bash curl -X POST "https://app.documenso.com/api/v2/template/create" \ - -H "Authorization: api_team_xxxxxxxxxxxxxxxx" \ + -H "Authorization: api_xxxxxxxxxxxxxxxx" \ -H "Content-Type: multipart/form-data" \ -F 'payload={ "title": "NDA Template", @@ -269,7 +269,7 @@ console.log('Created team template:', template.id); ```bash curl -X GET "https://app.documenso.com/api/v2/template" \ - -H "Authorization: api_team_xxxxxxxxxxxxxxxx" + -H "Authorization: api_xxxxxxxxxxxxxxxx" ```` diff --git a/apps/docs/content/docs/self-hosting/deployment/docker.mdx b/apps/docs/content/docs/self-hosting/deployment/docker.mdx index 68508e767..d8ba9c70a 100644 --- a/apps/docs/content/docs/self-hosting/deployment/docker.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/docker.mdx @@ -102,7 +102,7 @@ See [Email Configuration](/docs/self-hosting/configuration/email) for other tran | Variable | Description | Default | | ------------------------------------------- | -------------------------------------------------------------- | ------------------------- | | `PORT` | Port the application listens on | `3000` | -| `NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH` | Path to signing certificate inside container | `/opt/documenso/cert.p12` | +| `NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH` | Path to signing certificate inside container — set to the volume-mount path (e.g. `/opt/documenso/cert.p12`). Only Docker Compose defaults this; plain `docker run` must set it explicitly | - | | `NEXT_PRIVATE_SIGNING_PASSPHRASE` | Passphrase for the signing certificate | - | | `NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS` | Base64-encoded `.p12` certificate (alternative to file path) | - | | `NEXT_PUBLIC_UPLOAD_TRANSPORT` | Document storage: `database` or `s3` | `database` | @@ -136,6 +136,7 @@ docker run -d \ -e NEXT_PUBLIC_WEBAPP_URL="https://sign.example.com" \ -e NEXT_PRIVATE_INTERNAL_WEBAPP_URL="http://localhost:3000" \ -e NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@db-host:5432/documenso" \ + -e NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH="/opt/documenso/cert.p12" \ -e NEXT_PRIVATE_SIGNING_PASSPHRASE="your-certificate-password" \ -e NEXT_PRIVATE_SMTP_TRANSPORT="smtp-auth" \ -e NEXT_PRIVATE_SMTP_HOST="smtp.example.com" \ @@ -154,6 +155,12 @@ A signing certificate is required for document signing. You have two options for - **Volume mount** — mount a `.p12` file from the host into the container at `/opt/documenso/cert.p12` (shown above). This is the simplest approach for small to moderate deployments. - **Base64-encoded contents** — set `NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS` with the base64-encoded certificate string. Use this when file mounting is not available (e.g., Railway, Vercel). + + Plain `docker run` deployments must set `NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH` explicitly. This + prevents production deployments from accidentally using the insecure example certificate. + Docker Compose sets the file path for you. + + For production deployments that require Adobe Approved Trust List recognition, consider using a [Google Cloud HSM](/docs/self-hosting/configuration/signing-certificate/google-cloud-hsm) or another external HSM. @@ -178,6 +185,7 @@ NEXT_PUBLIC_WEBAPP_URL=https://sign.example.com NEXT_PRIVATE_INTERNAL_WEBAPP_URL=http://localhost:3000 NEXT_PRIVATE_DATABASE_URL=postgresql://user:password@db-host:5432/documenso NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@db-host:5432/documenso +NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/opt/documenso/cert.p12 NEXT_PRIVATE_SIGNING_PASSPHRASE=your-certificate-password NEXT_PRIVATE_SMTP_TRANSPORT=smtp-auth NEXT_PRIVATE_SMTP_HOST=smtp.example.com @@ -203,6 +211,12 @@ docker run -d \ Documenso provides health check endpoints for monitoring: + + If a certificate is mounted but signing fails, ensure `NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH` + explicitly points to its path inside the container. Production does not use the development + example certificate as a fallback. + + | Endpoint | Purpose | | ------------------------- | -------------------------------------------------------------- | | `/api/health` | Checks database connectivity and certificate status | diff --git a/apps/docs/content/docs/users/organisations/preferences/document.mdx b/apps/docs/content/docs/users/organisations/preferences/document.mdx index 1f4e82c08..d81252325 100644 --- a/apps/docs/content/docs/users/organisations/preferences/document.mdx +++ b/apps/docs/content/docs/users/organisations/preferences/document.mdx @@ -34,7 +34,7 @@ To access the preferences, navigate to either the organisation or teams settings | **Default Recipients** | Recipients that are automatically added to new documents. Can be overridden per document. | | **Default Envelope Expiration** | How long recipients have to sign before the signing link expires. See [recipient expiration](/docs/users/documents/advanced/recipient-expiration). | | **Default Signing Reminders** | When and how often to email recipients who have not yet signed. See [signing reminders](/docs/users/documents/advanced/signing-reminders). | -| **Delegate Document Ownership** | Allow team API tokens to delegate document ownership to another team member. | +| **Delegate Document Ownership** | By default, documents created with a team API token are owned by the user who created the token. Enable this setting to let supported API requests assign ownership to another team member. | | **AI Features** | Enable AI-powered features such as automatic recipient detection. Only shown if AI features are configured on the instance. | Document visibility, language, and signature settings can be overridden per document. From bf406aa9433c135daeab82d03c793ef2ca5dd9b8 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Tue, 1 Sep 2026 14:11:58 +1000 Subject: [PATCH 28/64] chore: upgrade libpdf (#3323) --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf266782c..5fa83778f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "dependencies": { "@ai-sdk/google-vertex": "5.0.48", "@documenso/prisma": "*", - "@libpdf/core": "^0.4.1", + "@libpdf/core": "^0.4.2", "@lingui/conf": "^5.6.0", "@lingui/core": "^5.6.0", "@marsidev/react-turnstile": "^1.5.0", @@ -4802,9 +4802,9 @@ "license": "MIT" }, "node_modules/@libpdf/core": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@libpdf/core/-/core-0.4.1.tgz", - "integrity": "sha512-DWGxWw1na8oFPixz+b6kOgu4tMD8xJLDgyPGVUNqIswO5POHAxsqmTvUvDW0IrwHP7kFRHBV3I3T/KhTABf9rA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@libpdf/core/-/core-0.4.2.tgz", + "integrity": "sha512-lbkIqLDZCCxjLpiC+8/Xvaru/ME7iVVoihl9tLqbp/CDUWZNF0q3u7s2tBJB9wRW/SzUWID6YPFvBWws770hrQ==", "license": "MIT", "dependencies": { "@noble/ciphers": "^2.2.0", diff --git a/package.json b/package.json index 4770c9eec..a8d78aed9 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "dependencies": { "@ai-sdk/google-vertex": "5.0.48", "@documenso/prisma": "*", - "@libpdf/core": "^0.4.1", + "@libpdf/core": "^0.4.2", "@lingui/conf": "^5.6.0", "@lingui/core": "^5.6.0", "@prisma/extension-read-replicas": "^0.4.1", From 3ec877a68bc423373220f9ee2fda3d93ba368680 Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Tue, 1 Sep 2026 16:12:08 +1000 Subject: [PATCH 29/64] fix: add patches back to dockerfile (#3324) --- docker/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index 0b5923a05..fa2be3083 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -76,6 +76,7 @@ COPY --from=builder /app/out/json/ . COPY --from=builder /app/out/package-lock.json ./package-lock.json COPY --from=builder /app/lingui.config.ts ./lingui.config.ts +COPY --from=builder /app/patches ./patches RUN npm ci @@ -114,6 +115,8 @@ WORKDIR /app COPY --from=builder --chown=nodejs:nodejs /app/out/json/ . # Copy the tailwind config files across COPY --from=builder --chown=nodejs:nodejs /app/out/full/packages/tailwind-config ./packages/tailwind-config +# Copy the patches across +COPY --from=builder --chown=nodejs:nodejs /app/patches ./patches RUN npm ci --only=production From cbb1cf7bef381f68db76bc35fef674430f7f983b Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Fri, 4 Sep 2026 01:17:42 +0300 Subject: [PATCH 30/64] fix: default unset signing transport to local (#3309) `/api/health` and `/api/certificate-status` reported the cert as available when `NEXT_PRIVATE_SIGNING_TRANSPORT` was unset, even though sealing defaults to the local P12 and fails if it is missing, unreadable, or expired. --- .../app/routes/api+/certificate-status.ts | 4 +-- apps/remix/app/routes/api+/health.ts | 2 +- packages/lib/constants/app.ts | 2 ++ packages/lib/server-only/cert/cert-status.ts | 36 ++++++++++++------- packages/signing/index.ts | 4 +-- packages/signing/transports/local.ts | 14 ++++++-- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/apps/remix/app/routes/api+/certificate-status.ts b/apps/remix/app/routes/api+/certificate-status.ts index eb8ae6cfd..5e4ea8be4 100644 --- a/apps/remix/app/routes/api+/certificate-status.ts +++ b/apps/remix/app/routes/api+/certificate-status.ts @@ -1,8 +1,8 @@ import { getCertificateStatus } from '@documenso/lib/server-only/cert/cert-status'; -export const loader = () => { +export const loader = async () => { try { - const certStatus = getCertificateStatus(); + const certStatus = await getCertificateStatus(); return Response.json({ isAvailable: certStatus.isAvailable, diff --git a/apps/remix/app/routes/api+/health.ts b/apps/remix/app/routes/api+/health.ts index c43ac1478..1cf8ccba9 100644 --- a/apps/remix/app/routes/api+/health.ts +++ b/apps/remix/app/routes/api+/health.ts @@ -22,7 +22,7 @@ export const loader = async () => { } try { - const certStatus = getCertificateStatus(); + const certStatus = await getCertificateStatus(); if (certStatus.isAvailable) { checks.certificate = { status: 'ok' }; diff --git a/packages/lib/constants/app.ts b/packages/lib/constants/app.ts index 9740fae22..17ded9d66 100644 --- a/packages/lib/constants/app.ts +++ b/packages/lib/constants/app.ts @@ -93,6 +93,8 @@ export const NEXT_PRIVATE_USE_PLAYWRIGHT_PDF = () => env('NEXT_PRIVATE_USE_PLAYW export const NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY = () => env('NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY'); +export const NEXT_PRIVATE_SIGNING_TRANSPORT = () => env('NEXT_PRIVATE_SIGNING_TRANSPORT') || 'local'; + /** * Whether this Documenso instance is running in CSC (Cloud Signature Consortium) mode. * diff --git a/packages/lib/server-only/cert/cert-status.ts b/packages/lib/server-only/cert/cert-status.ts index 737989eea..a3c0fd222 100644 --- a/packages/lib/server-only/cert/cert-status.ts +++ b/packages/lib/server-only/cert/cert-status.ts @@ -1,26 +1,36 @@ -import * as fs from 'node:fs'; +import { X509Certificate } from 'node:crypto'; -import { env } from '@documenso/lib/utils/env'; +import { createLocalSigner } from '@documenso/signing/transports/local'; -export const getCertificateStatus = () => { - if (env('NEXT_PRIVATE_SIGNING_TRANSPORT') !== 'local') { +import { NEXT_PRIVATE_SIGNING_TRANSPORT } from '../../constants/app'; + +/** + * Whether the local P12 opens with the configured passphrase and is in date. + * Skips AIA so this stays offline. gcloud-hsm and csc always report available. + */ +export const getCertificateStatus = async () => { + const transport = NEXT_PRIVATE_SIGNING_TRANSPORT(); + + // Cannot inspect a remote HSM or CSC provider from this process. + if (transport === 'gcloud-hsm' || transport === 'csc') { return { isAvailable: true }; } - if (env('NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS')) { - return { isAvailable: true }; + // Anything else (typo, leftover `http`) would throw at seal time. + if (transport !== 'local') { + return { isAvailable: false }; } - const defaultPath = env('NODE_ENV') === 'production' ? '/opt/documenso/cert.p12' : './example/cert.p12'; - - const filePath = env('NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH') || defaultPath; - try { - fs.accessSync(filePath, fs.constants.F_OK | fs.constants.R_OK); + const signer = await createLocalSigner({ buildChain: false }); - const stats = fs.statSync(filePath); + const certificate = new X509Certificate(Buffer.from(signer.certificate)); - return { isAvailable: stats.size > 0 }; + const now = new Date(); + + const isWithinValidityPeriod = new Date(certificate.validFrom) <= now && now <= new Date(certificate.validTo); + + return { isAvailable: isWithinValidityPeriod }; } catch { return { isAvailable: false }; } diff --git a/packages/signing/index.ts b/packages/signing/index.ts index 45af28441..d5f6c2f9b 100644 --- a/packages/signing/index.ts +++ b/packages/signing/index.ts @@ -1,9 +1,9 @@ import { + NEXT_PRIVATE_SIGNING_TRANSPORT, NEXT_PRIVATE_USE_LEGACY_SIGNING_SUBFILTER, NEXT_PUBLIC_SIGNING_CONTACT_INFO, NEXT_PUBLIC_WEBAPP_URL, } from '@documenso/lib/constants/app'; -import { env } from '@documenso/lib/utils/env'; import type { PDF, Signer } from '@libpdf/core'; import { match } from 'ts-pattern'; @@ -22,7 +22,7 @@ const getSigner = async () => { return signer; } - const transport = env('NEXT_PRIVATE_SIGNING_TRANSPORT') || 'local'; + const transport = NEXT_PRIVATE_SIGNING_TRANSPORT(); // eslint-disable-next-line require-atomic-updates signer = await match(transport) diff --git a/packages/signing/transports/local.ts b/packages/signing/transports/local.ts index a6e1698a2..1635e613b 100644 --- a/packages/signing/transports/local.ts +++ b/packages/signing/transports/local.ts @@ -22,10 +22,20 @@ const loadP12 = (): Uint8Array => { throw new Error('No certificate found for local signing'); }; -export const createLocalSigner = async () => { +export type CreateLocalSignerOptions = { + /** + * Fetch missing intermediates via AIA. Leave on for sealing. + * Turn off for health checks so they do not hit the network. + * + * @default true + */ + buildChain?: boolean; +}; + +export const createLocalSigner = async ({ buildChain = true }: CreateLocalSignerOptions = {}) => { const p12 = loadP12(); return await P12Signer.create(p12, env('NEXT_PRIVATE_SIGNING_PASSPHRASE') || '', { - buildChain: true, + buildChain, }); }; From dabb7b7a0d71abdbecb1f40e6d2a049b46a77cf9 Mon Sep 17 00:00:00 2001 From: Nathan Delhaye Date: Fri, 4 Sep 2026 04:26:01 +0200 Subject: [PATCH 31/64] fix: increase signature placeholder size when a timestamp authority is configured (#3328) --- packages/signing/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/signing/index.ts b/packages/signing/index.ts index d5f6c2f9b..acb1c00bb 100644 --- a/packages/signing/index.ts +++ b/packages/signing/index.ts @@ -49,6 +49,11 @@ export const signPdf = async ({ pdf }: SignOptions) => { timestampAuthority: tsa ?? undefined, longTermValidation: !!tsa, archivalTimestamp: !!tsa, + // A B-LTA signature (signer chain + RFC 3161 timestamp token + LTV + // revocation data) can exceed the 12288-byte default placeholder, + // depending on the signing certificate chain and the TSA responder. + // The unused portion is zero-padding, so over-reserving is cheap. + estimatedSize: tsa ? 32768 : undefined, }); return bytes; From 30a6b19b478f1cc3bec373d3ed182df53eac82ef Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Fri, 4 Sep 2026 12:29:02 +1000 Subject: [PATCH 32/64] chore: upgrade to node 24 lts and clean up docker image (#3332) Upgrade to Node 24 LTS, using the alpine 3.23 tag to handle issues with streaming zip files on 24.16 which hangs npm ci. Pin npm to 11.19.1 for min-release-age-exclude support. Slim the runner image by dropping dev deps, the react-email CLI, and esbuild, none of which run in production. Install turbo from the lockfile version instead of a hardcoded one. --- .github/actions/node-install/action.yml | 2 +- README.md | 2 +- .../docs/self-hosting/deployment/manual.mdx | 4 +- .../getting-started/requirements.mdx | 6 +-- apps/remix/Dockerfile.bun | 25 ------------- apps/remix/Dockerfile.pnpm | 26 ------------- docker/Dockerfile | 37 +++++++++++++------ package-lock.json | 35 ++++++++++++++---- package.json | 6 +-- packages/prisma/package.json | 10 ++--- 10 files changed, 68 insertions(+), 85 deletions(-) delete mode 100644 apps/remix/Dockerfile.bun delete mode 100644 apps/remix/Dockerfile.pnpm diff --git a/.github/actions/node-install/action.yml b/.github/actions/node-install/action.yml index b01a28740..fb208e916 100644 --- a/.github/actions/node-install/action.yml +++ b/.github/actions/node-install/action.yml @@ -2,7 +2,7 @@ name: 'Setup node' inputs: node_version: required: false - default: v22.x + default: v24.x runs: using: 'composite' diff --git a/README.md b/README.md index a1ed84f30..ad4d7c5b9 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Contact us if you are interested in our Enterprise plan for large organizations To run Documenso locally, you will need -- Node.js (v22 or above) +- Node.js (v24 or above) - Postgres SQL Database - Docker (optional) diff --git a/apps/docs/content/docs/self-hosting/deployment/manual.mdx b/apps/docs/content/docs/self-hosting/deployment/manual.mdx index d6dc4fda5..70f7da640 100644 --- a/apps/docs/content/docs/self-hosting/deployment/manual.mdx +++ b/apps/docs/content/docs/self-hosting/deployment/manual.mdx @@ -14,8 +14,8 @@ import { Step, Steps } from 'fumadocs-ui/components/steps'; ## Prerequisites -- Node.js 22 or later -- npm 11 or later +- Node.js 24 or later +- npm 11.17 or later - PostgreSQL 14 or later - A Linux server (for systemd service setup) diff --git a/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx b/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx index c64bd081e..b75069906 100644 --- a/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx +++ b/apps/docs/content/docs/self-hosting/getting-started/requirements.mdx @@ -141,8 +141,8 @@ If building from source (not using Docker images): | Requirement | Version | | ----------- | ------- | -| Node.js | 22+ | -| npm | 11+ | +| Node.js | 24+ | +| npm | 11.17+ | --- @@ -169,7 +169,7 @@ Documenso runs on: | MySQL/MariaDB | PostgreSQL-specific features required | | SQLite | Not suitable for production workloads | | MongoDB | Relational database required | -| Node.js < 22 | Modern JavaScript features required | +| Node.js < 24 | Modern JavaScript features required | --- diff --git a/apps/remix/Dockerfile.bun b/apps/remix/Dockerfile.bun deleted file mode 100644 index 973038e8a..000000000 --- a/apps/remix/Dockerfile.bun +++ /dev/null @@ -1,25 +0,0 @@ -FROM oven/bun:1 AS dependencies-env -COPY . /app - -FROM dependencies-env AS development-dependencies-env -COPY ./package.json bun.lockb /app/ -WORKDIR /app -RUN bun i --frozen-lockfile - -FROM dependencies-env AS production-dependencies-env -COPY ./package.json bun.lockb /app/ -WORKDIR /app -RUN bun i --production - -FROM dependencies-env AS build-env -COPY ./package.json bun.lockb /app/ -COPY --from=development-dependencies-env /app/node_modules /app/node_modules -WORKDIR /app -RUN bun run build - -FROM dependencies-env -COPY ./package.json bun.lockb /app/ -COPY --from=production-dependencies-env /app/node_modules /app/node_modules -COPY --from=build-env /app/build /app/build -WORKDIR /app -CMD ["bun", "run", "start"] \ No newline at end of file diff --git a/apps/remix/Dockerfile.pnpm b/apps/remix/Dockerfile.pnpm deleted file mode 100644 index 57916afc2..000000000 --- a/apps/remix/Dockerfile.pnpm +++ /dev/null @@ -1,26 +0,0 @@ -FROM node:20-alpine AS dependencies-env -RUN npm i -g pnpm -COPY . /app - -FROM dependencies-env AS development-dependencies-env -COPY ./package.json pnpm-lock.yaml /app/ -WORKDIR /app -RUN pnpm i --frozen-lockfile - -FROM dependencies-env AS production-dependencies-env -COPY ./package.json pnpm-lock.yaml /app/ -WORKDIR /app -RUN pnpm i --prod --frozen-lockfile - -FROM dependencies-env AS build-env -COPY ./package.json pnpm-lock.yaml /app/ -COPY --from=development-dependencies-env /app/node_modules /app/node_modules -WORKDIR /app -RUN pnpm build - -FROM dependencies-env -COPY ./package.json pnpm-lock.yaml /app/ -COPY --from=production-dependencies-env /app/node_modules /app/node_modules -COPY --from=build-env /app/build /app/build -WORKDIR /app -CMD ["pnpm", "start"] \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index fa2be3083..22cad2ecb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,7 @@ ########################### # BASE CONTAINER # ########################### -FROM node:22-alpine3.22 AS base +FROM node:24-alpine3.23 AS base RUN apk add --no-cache openssl RUN apk add --no-cache font-freefont @@ -19,7 +19,10 @@ WORKDIR /app COPY . . -RUN npm install -g "turbo@^2.10.0" +# Install the exact turbo version resolved in the lockfile, without installing +# the rest of the dependency tree (prune must run before any npm ci). +RUN TURBO_VERSION="$(jq -r '.packages["node_modules/turbo"].version' package-lock.json)" \ + && npm install -g "turbo@${TURBO_VERSION}" # Outputs to the /out folder # source: https://turbo.build/repo/docs/reference/command-line-reference/prune#--docker @@ -39,9 +42,9 @@ RUN apk add --no-cache make cmake g++ openssl bash WORKDIR /app # Disable husky from installing hooks -ENV HUSKY 0 -ENV DOCKER_OUTPUT 1 -ENV NEXT_TELEMETRY_DISABLED 1 +ENV HUSKY=0 +ENV DOCKER_OUTPUT=1 +ENV NEXT_TELEMETRY_DISABLED=1 # Encryption keys ARG NEXT_PRIVATE_ENCRYPTION_KEY="CAFEBABE" @@ -85,17 +88,17 @@ COPY --from=builder /app/out/full/ . # Finally copy the turbo.json file so that we can run turbo commands COPY turbo.json turbo.json -RUN npm install -g "turbo@^2.10.0" +ENV NODE_OPTIONS="--max-old-space-size=8192" -RUN turbo run build --filter=@documenso/remix... +RUN npx turbo run build --filter=@documenso/remix... ########################### # RUNNER CONTAINER # ########################### FROM base AS runner -ENV HUSKY 0 -ENV DOCKER_OUTPUT 1 +ENV HUSKY=0 +ENV DOCKER_OUTPUT=1 # Telemetry credentials (baked into image at build time, can be disabled at runtime) ARG NEXT_PRIVATE_TELEMETRY_KEY="" @@ -118,7 +121,16 @@ COPY --from=builder --chown=nodejs:nodejs /app/out/full/packages/tailwind-config # Copy the patches across COPY --from=builder --chown=nodejs:nodejs /app/patches ./patches -RUN npm ci --only=production +RUN npm ci --omit=dev --no-audit --no-fund && npm cache clean --force + +# Strip build-time residue that ships as production dependencies but is never +# executed at runtime. +RUN rm -rf \ + node_modules/react-email/dist/cli \ + node_modules/esbuild \ + node_modules/@esbuild \ + node_modules/.bin/esbuild \ + node_modules/.bin/email # Automatically leverage output traces to reduce image size # https://nodejs.org/docs/advanced-features/output-file-tracing @@ -129,8 +141,9 @@ COPY --from=installer --chown=nodejs:nodejs /app/apps/remix/public ./apps/remix/ COPY --from=installer --chown=nodejs:nodejs /app/packages/prisma/schema.prisma ./packages/prisma/schema.prisma COPY --from=installer --chown=nodejs:nodejs /app/packages/prisma/migrations ./packages/prisma/migrations -# Generate the prisma client again -RUN npx prisma generate --schema ./packages/prisma/schema.prisma +# Generate the prisma client again, this time only targeting the client generator +RUN npx prisma generate --schema ./packages/prisma/schema.prisma --generator client \ + && npm cache clean --force # Get the start script from docker/ diff --git a/package-lock.json b/package-lock.json index 5fa83778f..d7b6c7081 100644 --- a/package-lock.json +++ b/package-lock.json @@ -102,8 +102,8 @@ "zod-prisma-types": "3.3.5" }, "engines": { - "node": ">=22.0.0", - "npm": ">=11.11.0" + "node": ">=24.0.0", + "npm": ">=11.17.0" } }, "apps/docs": { @@ -3153,6 +3153,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.5.0.tgz", "integrity": "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@chevrotain/gast": "10.5.0", @@ -3164,6 +3165,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.5.0.tgz", "integrity": "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@chevrotain/types": "10.5.0", @@ -3174,12 +3176,14 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.5.0.tgz", "integrity": "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@chevrotain/utils": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.5.0.tgz", "integrity": "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@commitlint/cli": { @@ -5723,6 +5727,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/@mrleebo/prisma-ast/-/prisma-ast-0.13.1.tgz", "integrity": "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==", + "dev": true, "license": "MIT", "dependencies": { "chevrotain": "^10.5.0", @@ -10295,12 +10300,14 @@ "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/dmmf/-/dmmf-6.19.3.tgz", "integrity": "sha512-+D6v7RIF21bJrZAXiiIdW0qR73TleYVCqTDozokdEHdGeqN997O7jJW5z+43s5CVwWTZJIwFGpoeXxDDyXDVxA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/driver-adapter-utils": { "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-6.19.3.tgz", "integrity": "sha512-UUxn6VLfKKVqm5n9vexOQgFJ9TCBIxupb7F5FzLQ6iM2VV0WZxhgzbQVqBDsGY+VmQLmqaSoKRusEfy3O5KZpA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.19.3" @@ -10349,12 +10356,14 @@ "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/generator/-/generator-6.19.3.tgz", "integrity": "sha512-rzHJaIZEnEDUWNjjFAimsyMCS9osPxwbwiAbymwFprSHJSAglMxMDVU+xbQUCLeDsjUF09W5ag/aBPL2t3YqgA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/generator-helper": { "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-6.19.3.tgz", "integrity": "sha512-13S8ngSWVKcyuRFqaK/JGMyovjQC5sOKJ9A+ufqePQWeIUbvKO2QY2CmhcV4JAa2vuN22//4Sip5mORVKwS0sw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.19.3", @@ -10375,6 +10384,7 @@ "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/internals/-/internals-6.19.3.tgz", "integrity": "sha512-1V5ba+BNtGFFlgoA8ecyAbjmoMWzIrEuebmLbJpeS7qbhnY6vbc1OZ6qc55lI/VAkfdALSL5vePG5KF9P8feLw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/config": "6.19.3", @@ -10405,18 +10415,21 @@ "version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", "resolved": "https://registry.npmjs.org/@prisma/prisma-schema-wasm/-/prisma-schema-wasm-7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7.tgz", "integrity": "sha512-/5JrsJQAOIWSl+9WMM/0ugd737kT9zdMNr7EFaP7ogeMxAhxQ78uaOV6JYGEocD8LC0gZx7MXmVE/CTfYdJ2iA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/schema-engine-wasm": { "version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", "resolved": "https://registry.npmjs.org/@prisma/schema-engine-wasm/-/schema-engine-wasm-7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7.tgz", "integrity": "sha512-mXtzeePkSdqpr/HAIclqzQEf+tBzLawy7NQ9AaRCfg8N/cruavpsocgbSwOOfV7JTk9JubyzKuR3tp2bNNuWbQ==", + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/schema-files-loader": { "version": "6.19.3", "resolved": "https://registry.npmjs.org/@prisma/schema-files-loader/-/schema-files-loader-6.19.3.tgz", "integrity": "sha512-rnoL2PgopghakRZLCZwj+d7LPvjbY9mFholFWuibEKzwO7aqS16s60Hz4wxAnKwqOcS/M6pV7QLrsHBYnNR0KA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/prisma-schema-wasm": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", @@ -16274,6 +16287,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.5.0.tgz", "integrity": "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@chevrotain/cst-dts-gen": "10.5.0", @@ -16625,6 +16639,7 @@ "version": "13.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "dev": true, "license": "MIT" }, "node_modules/collapse-white-space": { @@ -19871,6 +19886,7 @@ "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -22537,6 +22553,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -26383,6 +26400,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/prisma-json-types-generator/-/prisma-json-types-generator-3.6.2.tgz", "integrity": "sha512-WX/oENQ0S74r/Wgd2uuHT5i3KbnwLFCP2Fq5ISzrXkus/htOC4uCaQPYuGP2m/wSeKZZCw1RxptTlD+ib7Ht/A==", + "dev": true, "license": "MIT", "dependencies": { "@prisma/generator-helper": "^6.16.1", @@ -26408,6 +26426,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/prisma-kysely/-/prisma-kysely-2.3.0.tgz", "integrity": "sha512-/+VF2t2DlY+t/27hhyH5ULWxBAAsMBPgOo8Ltq7uXpBz49lUf4XuO1ff9HV0l7J3aDojG+YyczEvY0og9uRqsw==", + "dev": true, "license": "MIT", "dependencies": { "@mrleebo/prisma-ast": "^0.13.1", @@ -27608,6 +27627,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true, "license": "MIT" }, "node_modules/rehype-raw": { @@ -31654,6 +31674,7 @@ "version": "3.3.5", "resolved": "https://registry.npmjs.org/zod-prisma-types/-/zod-prisma-types-3.3.5.tgz", "integrity": "sha512-PDuRRCdX1d6ch6UclNvrqM1SLb2qvuaQPvZT/OHRrcxOQqQUnCz009aBc1uxuwMho1+d42TTDCQr+HPXhTSJtQ==", + "dev": true, "license": "MIT", "dependencies": { "@prisma/dmmf": "^6.16.3", @@ -32410,17 +32431,17 @@ "nanoid": "^5.1.6", "prisma": "^6.19.0", "prisma-extension-kysely": "^3.0.0", - "prisma-json-types-generator": "^3.6.2", - "prisma-kysely": "^2.3.0", "ts-pattern": "^5.9.0", - "zod": "^3.25.76", - "zod-prisma-types": "3.3.5" + "zod": "^3.25.76" }, "devDependencies": { "dotenv": "^17.2.3", "dotenv-cli": "^11.0.0", + "prisma-json-types-generator": "^3.6.2", + "prisma-kysely": "^2.3.0", "tsx": "^4.23.1", - "typescript": "5.6.2" + "typescript": "5.6.2", + "zod-prisma-types": "3.3.5" } }, "packages/prisma/node_modules/@esbuild/aix-ppc64": { diff --git a/package.json b/package.json index a8d78aed9..557850100 100644 --- a/package.json +++ b/package.json @@ -41,10 +41,10 @@ "translate:extract": "lingui extract --clean", "translate:compile": "lingui compile" }, - "packageManager": "npm@11.11.0", + "packageManager": "npm@11.19.1", "engines": { - "npm": ">=11.11.0", - "node": ">=22.0.0" + "npm": ">=11.17.0", + "node": ">=24.0.0" }, "devDependencies": { "@biomejs/biome": "2.4.8", diff --git a/packages/prisma/package.json b/packages/prisma/package.json index 67f2ae110..44992d6e4 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -26,16 +26,16 @@ "nanoid": "^5.1.6", "prisma": "^6.19.0", "prisma-extension-kysely": "^3.0.0", - "prisma-kysely": "^2.3.0", - "prisma-json-types-generator": "^3.6.2", "ts-pattern": "^5.9.0", - "zod": "^3.25.76", - "zod-prisma-types": "3.3.5" + "zod": "^3.25.76" }, "devDependencies": { "dotenv": "^17.2.3", "dotenv-cli": "^11.0.0", + "prisma-kysely": "^2.3.0", + "prisma-json-types-generator": "^3.6.2", "tsx": "^4.23.1", - "typescript": "5.6.2" + "typescript": "5.6.2", + "zod-prisma-types": "3.3.5" } } From 4aa3583e89432e5aec23b57a2a8739e245b27033 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Fri, 4 Sep 2026 08:41:11 +0300 Subject: [PATCH 33/64] fix: temporary fix for British to US spelling (#3329) --- .../app-tests/e2e/admin/global-search.spec.ts | 2 +- .../organisations/delete-organisation.spec.ts | 2 +- .../update-organisation-member-role.spec.ts | 10 +- .../documents/bulk-document-actions.spec.ts | 6 +- .../e2e/documents/cancel-documents.spec.ts | 14 +- .../organisations/manage-organisation.spec.ts | 44 +- .../organisation-quota-banner.spec.ts | 6 +- .../organisation-team-preferences.spec.ts | 10 +- .../e2e/settings/unified-settings.spec.ts | 6 +- packages/lib/translations/en/web.po | 530 +++++++++--------- 10 files changed, 315 insertions(+), 315 deletions(-) diff --git a/packages/app-tests/e2e/admin/global-search.spec.ts b/packages/app-tests/e2e/admin/global-search.spec.ts index ab9f2d698..1a2a5c072 100644 --- a/packages/app-tests/e2e/admin/global-search.spec.ts +++ b/packages/app-tests/e2e/admin/global-search.spec.ts @@ -10,7 +10,7 @@ test.describe.configure({ mode: 'parallel' }); const nanoid = customAlphabet('1234567890abcdef', 10); -const ADMIN_PROMPT_PLACEHOLDER = 'Search documents, users, organisations…'; +const ADMIN_PROMPT_PLACEHOLDER = 'Search documents, users, organizations…'; test('[ADMIN][GLOBAL_SEARCH]: numeric query shows verified user result and navigates', async ({ page }) => { const { user: adminUser } = await seedUser({ isAdmin: true }); diff --git a/packages/app-tests/e2e/admin/organisations/delete-organisation.spec.ts b/packages/app-tests/e2e/admin/organisations/delete-organisation.spec.ts index aa44a8f0e..eb0722fd8 100644 --- a/packages/app-tests/e2e/admin/organisations/delete-organisation.spec.ts +++ b/packages/app-tests/e2e/admin/organisations/delete-organisation.spec.ts @@ -411,7 +411,7 @@ test('[ADMIN][DELETE_ORG]: the original owner loses access after deletion', asyn }); // They should NOT see the organisation settings heading for this org. - await expect(page.getByText('Organisation Settings')).not.toBeVisible(); + await expect(page.getByText('Organization Settings')).not.toBeVisible(); }); // ─── Access control: UI ────────────────────────────────────────────────────── diff --git a/packages/app-tests/e2e/admin/organisations/update-organisation-member-role.spec.ts b/packages/app-tests/e2e/admin/organisations/update-organisation-member-role.spec.ts index c54bd94bd..73be9d65a 100644 --- a/packages/app-tests/e2e/admin/organisations/update-organisation-member-role.spec.ts +++ b/packages/app-tests/e2e/admin/organisations/update-organisation-member-role.spec.ts @@ -50,9 +50,9 @@ test('[ADMIN]: promote member to owner', async ({ page }) => { }); // Verify we're on the admin organisation page - await expect(page.getByText(`Manage organisation`)).toBeVisible(); + await expect(page.getByText(`Manage organization`)).toBeVisible(); - await expect(page.getByLabel('Organisation Name')).toHaveValue(organisation.name); + await expect(page.getByLabel('Organization Name')).toHaveValue(organisation.name); // Check that the organisation members table shows the correct roles const ownerRow = page.getByRole('row', { name: ownerUser.email }); @@ -356,7 +356,7 @@ test('[ADMIN]: error handling for invalid organisation', async ({ page }) => { }); // Should show 404 error - await expect(page.getByRole('heading', { name: 'Organisation not found' })).toBeVisible({ + await expect(page.getByRole('heading', { name: 'Organization not found' })).toBeVisible({ timeout: 10_000, }); }); @@ -525,8 +525,8 @@ test('[ADMIN]: verify organisation access after ownership change', async ({ page // Should be able to access organisation settings await expect(page.getByTestId('unified-settings-sidebar')).toBeVisible(); - await expect(page.getByLabel('Organisation Name*')).toBeVisible(); - await expect(page.getByLabel('Organisation Name*')).toBeEnabled(); + await expect(page.getByLabel('Organization Name*')).toBeVisible(); + await expect(page.getByLabel('Organization Name*')).toBeEnabled(); // Should have delete permissions await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible(); diff --git a/packages/app-tests/e2e/documents/bulk-document-actions.spec.ts b/packages/app-tests/e2e/documents/bulk-document-actions.spec.ts index 12282ca15..3d4632c59 100644 --- a/packages/app-tests/e2e/documents/bulk-document-actions.spec.ts +++ b/packages/app-tests/e2e/documents/bulk-document-actions.spec.ts @@ -408,7 +408,7 @@ test('[BULK_ACTIONS]: can cancel multiple pending documents', async ({ page }) = await dialog.getByRole('button', { name: 'Cancel documents' }).click(); - await expectToastTextToBeVisible(page, 'Documents cancelled'); + await expectToastTextToBeVisible(page, 'Documents canceled'); // Selection clears after a successful cancel. await expect(page.getByText(/\d+ selected/)).not.toBeVisible(); @@ -455,7 +455,7 @@ test('[BULK_ACTIONS]: bulk cancel only affects pending documents', async ({ page await dialog.getByRole('button', { name: 'Cancel documents' }).click(); // Only one of the three was pending, so this is a partial result. - await expectToastTextToBeVisible(page, 'Documents partially cancelled'); + await expectToastTextToBeVisible(page, 'Documents partially canceled'); const pendingEnvelope = await prisma.envelope.findFirstOrThrow({ where: { id: pending.id }, @@ -505,7 +505,7 @@ test('[BULK_ACTIONS]: a MEMBER cannot bulk cancel documents they do not own', as // The server rejects the cancellation for a document the MEMBER does not own, // so it reports zero cancelled (a partial result with the document in failedIds). - await expectToastTextToBeVisible(page, 'Documents partially cancelled'); + await expectToastTextToBeVisible(page, 'Documents partially canceled'); // The document remains pending. const envelope = await prisma.envelope.findFirstOrThrow({ diff --git a/packages/app-tests/e2e/documents/cancel-documents.spec.ts b/packages/app-tests/e2e/documents/cancel-documents.spec.ts index d34ae532f..d8b3decb2 100644 --- a/packages/app-tests/e2e/documents/cancel-documents.spec.ts +++ b/packages/app-tests/e2e/documents/cancel-documents.spec.ts @@ -41,7 +41,7 @@ const cancelDocumentViaUi = async (page: Page, documentTitle: string, reason?: s await expect(page.getByRole('heading', { name: 'Are you sure?' })).toBeVisible(); if (reason) { - await page.getByPlaceholder('Add an optional reason for cancelling this document').fill(reason); + await page.getByPlaceholder('Add an optional reason for canceling this document').fill(reason); } await page.getByRole('button', { name: 'Cancel document' }).click(); @@ -58,13 +58,13 @@ test('[DOCUMENTS]: cancelling a pending document keeps it in the owner dashboard await cancelDocumentViaUi(page, 'Document 1 - Pending', 'No longer required'); - await expectToastTextToBeVisible(page, 'Document cancelled'); + await expectToastTextToBeVisible(page, 'Document canceled'); // The document must remain in the dashboard, unlike deleting a pending document. await checkDocumentCounts(page, { inbox: 0, pending: 0, cancelled: 1, all: 1 }); // The cancelled document is still listed. - await selectDocumentStatusFilter(page, 'Cancelled'); + await selectDocumentStatusFilter(page, 'Canceled'); await expect(page.getByRole('link', { name: 'Document 1 - Pending' })).toBeVisible(); // The envelope status is persisted as CANCELLED. @@ -95,7 +95,7 @@ test('[DOCUMENTS]: cancelling a pending document retains it for recipients', asy await cancelDocumentViaUi(page, 'Document 1 - Pending'); - await expectToastTextToBeVisible(page, 'Document cancelled'); + await expectToastTextToBeVisible(page, 'Document canceled'); await apiSignout({ page }); @@ -125,10 +125,10 @@ test('[DOCUMENTS]: a cancelled document can be deleted, hiding it from the owner }); await cancelDocumentViaUi(page, 'Document 1 - Pending'); - await expectToastTextToBeVisible(page, 'Document cancelled'); + await expectToastTextToBeVisible(page, 'Document canceled'); // Delete the now-cancelled document. Being terminal, it should soft delete (hide). - await selectDocumentStatusFilter(page, 'Cancelled'); + await selectDocumentStatusFilter(page, 'Canceled'); const documentActionBtn = page .locator('tr', { hasText: 'Document 1 - Pending' }) @@ -328,7 +328,7 @@ test('[DOCUMENTS]: a team ADMIN sees and can use the Cancel action on a document await cancelDocumentViaUi(page, 'Admin Cancellable Document'); - await expectToastTextToBeVisible(page, 'Document cancelled'); + await expectToastTextToBeVisible(page, 'Document canceled'); const envelope = await prisma.envelope.findFirstOrThrow({ where: { id: document.id }, diff --git a/packages/app-tests/e2e/organisations/manage-organisation.spec.ts b/packages/app-tests/e2e/organisations/manage-organisation.spec.ts index 23fcdedc6..2e4621394 100644 --- a/packages/app-tests/e2e/organisations/manage-organisation.spec.ts +++ b/packages/app-tests/e2e/organisations/manage-organisation.spec.ts @@ -29,11 +29,11 @@ test('[ORGANISATIONS]: create and delete organisation', async ({ page }) => { await page.waitForURL(`/settings/organisations`); await expectTextToBeVisible(page, 'No results found'); - await page.getByRole('button', { name: 'Create organisation' }).click(); + await page.getByRole('button', { name: 'Create organization' }).click(); - await page.getByLabel('Organisation Name*').fill('test'); + await page.getByLabel('Organization Name*').fill('test'); await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByText('Your organisation has been created').first()).toBeVisible(); + await expect(page.getByText('Your organization has been created').first()).toBeVisible(); await page.reload(); await page.getByRole('row').filter({ hasText: 'test' }).getByRole('link').nth(1).click(); @@ -53,12 +53,12 @@ test('[ORGANISATIONS]: manage general settings', async ({ page }) => { const updatedOrganisationId = `organisation-${Date.now()}`; // Update team. - await page.getByLabel('Organisation Name*').click(); - await page.getByLabel('Organisation Name*').clear(); - await page.getByLabel('Organisation Name*').fill(updatedOrganisationId); - await page.getByLabel('Organisation URL*').click(); - await page.getByLabel('Organisation URL*').clear(); - await page.getByLabel('Organisation URL*').fill(updatedOrganisationId); + await page.getByLabel('Organization Name*').click(); + await page.getByLabel('Organization Name*').clear(); + await page.getByLabel('Organization Name*').fill(updatedOrganisationId); + await page.getByLabel('Organization URL*').click(); + await page.getByLabel('Organization URL*').clear(); + await page.getByLabel('Organization URL*').fill(updatedOrganisationId); await page.getByRole('button', { name: 'Save changes' }).click(); @@ -277,8 +277,8 @@ test('[ORGANISATIONS]: manage groups and members', async ({ page }) => { // Create a custom group A with 3 members "ORGANISATION ADMIN" to check that they get the correct roles. await page.getByRole('button', { name: 'Create group' }).click(); await page.getByRole('textbox', { name: 'Group Name *' }).fill('CUSTOM_GROUP'); - await page.getByRole('combobox').filter({ hasText: 'Organisation Member' }).click(); - await page.getByRole('option', { name: 'Organisation Admin' }).click(); + await page.getByRole('combobox').filter({ hasText: 'Organization Member' }).click(); + await page.getByRole('option', { name: 'Organization Admin' }).click(); await page.getByTestId('group-members-picker').click(); await page.getByRole('option', { name: 'Member1' }).click(); await page.getByRole('option', { name: 'Member2' }).click(); @@ -291,16 +291,16 @@ test('[ORGANISATIONS]: manage groups and members', async ({ page }) => { await page.goto(`/o/${organisation.url}/settings/members`); // Confirm org roles have been applied to these members. - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(memberEmail1)).toBeVisible(); - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(memberEmail2)).toBeVisible(); - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(memberEmail3)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(memberEmail1)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(memberEmail2)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(memberEmail3)).toBeVisible(); // Test updating the group. await page.goto(`/o/${organisation.url}/settings/groups`); await page.getByRole('link', { name: 'Manage' }).click(); await page.getByRole('textbox', { name: 'Group Name *' }).fill('CUSTOM_GROUP_A'); - await page.getByRole('combobox').filter({ hasText: 'Organisation Admin' }).click(); - await page.getByRole('option', { name: 'Organisation Member' }).click(); + await page.getByRole('combobox').filter({ hasText: 'Organization Admin' }).click(); + await page.getByRole('option', { name: 'Organization Member' }).click(); // Remove Member3 by clicking the X on its chip in the multiselect. await page .getByTestId('group-members-picker') @@ -327,16 +327,16 @@ test('[ORGANISATIONS]: manage groups and members', async ({ page }) => { await page.goto(`/o/${organisation.url}/settings/members`); // Confirm admins still get admin roles. - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(adminEmail1)).toBeVisible(); - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(adminEmail2)).toBeVisible(); - await expect(page.getByRole('row').filter({ hasText: 'Organisation Admin' }).getByText(adminEmail3)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(adminEmail1)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(adminEmail2)).toBeVisible(); + await expect(page.getByRole('row').filter({ hasText: 'Organization Admin' }).getByText(adminEmail3)).toBeVisible(); // Create another custom group with 3 members with "ORGANISATION MEMBER" role. await page.goto(`/o/${organisation.url}/settings/groups`); await page.getByRole('button', { name: 'Create group' }).click(); await page.getByRole('textbox', { name: 'Group Name *' }).fill('CUSTOM_GROUP_B'); - await page.getByRole('combobox').filter({ hasText: 'Organisation Member' }).click(); - await page.getByRole('option', { name: 'Organisation Admin' }).click(); + await page.getByRole('combobox').filter({ hasText: 'Organization Member' }).click(); + await page.getByRole('option', { name: 'Organization Admin' }).click(); await page.getByTestId('group-members-picker').click(); await page.getByRole('option', { name: 'Member4' }).click(); await page.getByRole('option', { name: 'Member5' }).click(); @@ -537,6 +537,6 @@ test('[ORGANISATIONS]: leave organisation', async ({ page }) => { await page.getByRole('button', { name: 'Leave' }).click(); await page.getByRole('button', { name: 'Leave' }).click(); - await expect(page.getByText('You have successfully left this organisation').first()).toBeVisible(); + await expect(page.getByText('You have successfully left this organization').first()).toBeVisible(); await expect(page.getByText('No results found').first()).toBeVisible(); }); diff --git a/packages/app-tests/e2e/organisations/organisation-quota-banner.spec.ts b/packages/app-tests/e2e/organisations/organisation-quota-banner.spec.ts index 205bc437e..5fca9c0de 100644 --- a/packages/app-tests/e2e/organisations/organisation-quota-banner.spec.ts +++ b/packages/app-tests/e2e/organisations/organisation-quota-banner.spec.ts @@ -7,8 +7,8 @@ import { expect, test } from '@playwright/test'; import { apiSignin } from '../fixtures/authentication'; -const BANNER_EXCEEDED_TEXT = 'Your organisation has exceeded a fair use limit'; -const BANNER_NEARING_TEXT = 'Your organisation is approaching a fair use limit'; +const BANNER_EXCEEDED_TEXT = 'Your organization has exceeded a fair use limit'; +const BANNER_NEARING_TEXT = 'Your organization is approaching a fair use limit'; type SeedQuotaStateOptions = { organisationId: string; @@ -162,7 +162,7 @@ test('[QUOTA BANNER]: is hidden for free-claim organisations', async ({ page }) }); // Anchor on a stable element so banner-absence is meaningful (page fully loaded). - await expect(page.getByLabel('Organisation Name*')).toBeVisible(); + await expect(page.getByLabel('Organization Name*')).toBeVisible(); await expect(page.getByText(BANNER_EXCEEDED_TEXT)).toBeHidden(); await expect(page.getByRole('button', { name: 'Learn more' })).toBeHidden(); diff --git a/packages/app-tests/e2e/organisations/organisation-team-preferences.spec.ts b/packages/app-tests/e2e/organisations/organisation-team-preferences.spec.ts index 8c03ff72c..895b0c5aa 100644 --- a/packages/app-tests/e2e/organisations/organisation-team-preferences.spec.ts +++ b/packages/app-tests/e2e/organisations/organisation-team-preferences.spec.ts @@ -176,7 +176,7 @@ test('[ORGANISATIONS]: manage branding preferences', async ({ page }) => { // Test inheritance by setting team back to inherit from organisation await page.getByTestId('enable-branding').click(); - await page.getByRole('option', { name: 'Inherit from organisation' }).click(); + await page.getByRole('option', { name: 'Inherit from organization' }).click(); await page.getByRole('button', { name: 'Save changes' }).first().click(); await expect(page.getByText('Your branding preferences have been updated').first()).toBeVisible(); @@ -254,9 +254,9 @@ test('[ORGANISATIONS]: manage email preferences', async ({ page }) => { await page .getByTestId('inheritable-email-document-settings') .getByRole('combobox') - .filter({ hasText: 'Inherit from organisation' }) + .filter({ hasText: 'Inherit from organization' }) .click(); - await page.getByRole('option', { name: 'Override organisation settings' }).click(); + await page.getByRole('option', { name: 'Override organization settings' }).click(); // Update some email settings await page.getByRole('checkbox', { name: 'Email recipients with a signing request' }).uncheck(); @@ -308,8 +308,8 @@ test('[ORGANISATIONS]: manage email preferences', async ({ page }) => { // Test inheritance by setting team back to inherit from organisation await page.getByRole('textbox', { name: 'Reply to email' }).fill(''); - await page.getByRole('combobox').filter({ hasText: 'Override organisation settings' }).click(); - await page.getByRole('option', { name: 'Inherit from organisation' }).click(); + await page.getByRole('combobox').filter({ hasText: 'Override organization settings' }).click(); + await page.getByRole('option', { name: 'Inherit from organization' }).click(); await page.getByRole('button', { name: 'Save changes' }).first().click(); await expect(page.getByText('Your email preferences have been updated').first()).toBeVisible(); diff --git a/packages/app-tests/e2e/settings/unified-settings.spec.ts b/packages/app-tests/e2e/settings/unified-settings.spec.ts index 19b24aa6f..1375e55f3 100644 --- a/packages/app-tests/e2e/settings/unified-settings.spec.ts +++ b/packages/app-tests/e2e/settings/unified-settings.spec.ts @@ -248,7 +248,7 @@ test.describe('Unified Settings', () => { // Wait for the organisation page to actually render — asserting straight after // `waitForURL` can read the previous scope's still-mounted sidebar and pass falsely. - await expect(page.getByTestId('settings-scope-breadcrumb-chip')).toContainText('Organisation Settings'); + await expect(page.getByTestId('settings-scope-breadcrumb-chip')).toContainText('Organization Settings'); await expect(trigger).toContainText(selected.name); @@ -283,7 +283,7 @@ test.describe('Unified Settings', () => { // Selecting the inherit option stages the field back to inherited. await page.getByTestId('document-language-trigger').click(); - await page.getByRole('option', { name: /inherit from organisation/i }).click(); + await page.getByRole('option', { name: /inherit from organization/i }).click(); await expect(langStatus).toHaveText(/inherited/i); }); @@ -450,7 +450,7 @@ test.describe('Unified Settings', () => { // An empty group would just look broken, so it explains itself directly under the switcher. const emptyState = sidebar.getByTestId('unified-settings-organisation-empty-state'); await expect(emptyState).toBeVisible(); - await expect(emptyState).toContainText(/permission to manage this organisation/i); + await expect(emptyState).toContainText(/permission to manage this organization/i); // Team and account pages remain navigable. await expect(sidebar.getByTestId('unified-settings-nav-team-general')).toBeVisible(); diff --git a/packages/lib/translations/en/web.po b/packages/lib/translations/en/web.po index 980c3cfae..5580bdab8 100644 --- a/packages/lib/translations/en/web.po +++ b/packages/lib/translations/en/web.po @@ -46,7 +46,7 @@ msgstr "\"{placeholderEmail}\" on behalf of \"Team Name\" has invited you to sig #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx msgid "\"{title}\" has been successfully cancelled" -msgstr "\"{title}\" has been successfully cancelled" +msgstr "\"{title}\" has been successfully canceled" #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "\"{title}\" has been successfully deleted" @@ -99,13 +99,13 @@ msgstr "{0, plural, one {# character remaining} other {# characters remaining}}" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx msgid "{0, plural, one {# CSS rule was dropped during sanitisation.} other {# CSS rules were dropped during sanitisation.}}" -msgstr "{0, plural, one {# CSS rule was dropped during sanitisation.} other {# CSS rules were dropped during sanitisation.}}" +msgstr "{0, plural, one {# CSS rule was dropped during sanitization.} other {# CSS rules were dropped during sanitization.}}" #. placeholder {0}: result.cancelledCount #. placeholder {1}: result.failedIds.length #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "{0, plural, one {# document cancelled.} other {# documents cancelled.}} {1, plural, one {# document could not be cancelled.} other {# documents could not be cancelled.}}" -msgstr "{0, plural, one {# document cancelled.} other {# documents cancelled.}} {1, plural, one {# document could not be cancelled.} other {# documents could not be cancelled.}}" +msgstr "{0, plural, one {# document canceled.} other {# documents canceled.}} {1, plural, one {# document could not be canceled.} other {# documents could not be canceled.}}" #. placeholder {0}: successfulEnvelopeIds.length #: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx @@ -115,7 +115,7 @@ msgstr "{0, plural, one {# document downloaded.} other {# documents downloaded.} #. placeholder {0}: result.cancelledCount #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "{0, plural, one {# document has been cancelled.} other {# documents have been cancelled.}}" -msgstr "{0, plural, one {# document has been cancelled.} other {# documents have been cancelled.}}" +msgstr "{0, plural, one {# document has been canceled.} other {# documents have been canceled.}}" #. placeholder {0}: successfulEnvelopeIds.length #: apps/remix/app/components/dialogs/envelopes-bulk-download-dialog.tsx @@ -393,11 +393,11 @@ msgstr "{inviterName} <0>({inviterEmail})" #: packages/email/templates/document-cancel.tsx msgid "{inviterName} has cancelled the document {documentName}, you don't need to sign it anymore." -msgstr "{inviterName} has cancelled the document {documentName}, you don't need to sign it anymore." +msgstr "{inviterName} has canceled the document {documentName}, you don't need to sign it anymore." #: packages/email/template-components/template-document-cancel.tsx msgid "{inviterName} has cancelled the document<0/>\"{documentName}\"" -msgstr "{inviterName} has cancelled the document<0/>\"{documentName}\"" +msgstr "{inviterName} has canceled the document<0/>\"{documentName}\"" #. placeholder {0}: _(actionVerb).toLowerCase() #: packages/email/template-components/template-document-invite.tsx @@ -452,7 +452,7 @@ msgstr "{maximumEnvelopeItemCount, plural, one {You cannot upload more than # it #: apps/remix/app/components/dialogs/email-transport-delete-dialog.tsx msgid "{organisationClaimCount, plural, one {# Organisation claim} other {# Organisation claims}}" -msgstr "{organisationClaimCount, plural, one {# Organisation claim} other {# Organisation claims}}" +msgstr "{organisationClaimCount, plural, one {# Organization claim} other {# Organization claims}}" #: apps/remix/app/components/general/direct-template/direct-template-page.tsx msgid "{recipientActionVerb} document" @@ -544,11 +544,11 @@ msgstr "{user} authenticated with the signing provider" #: packages/lib/utils/document-audit-logs.ts msgid "{user} authorised the remote signature" -msgstr "{user} authorised the remote signature" +msgstr "{user} authorized the remote signature" #: packages/lib/utils/document-audit-logs.ts msgid "{user} cancelled the document" -msgstr "{user} cancelled the document" +msgstr "{user} canceled the document" #: packages/lib/utils/document-audit-logs.ts msgid "{user} CC'd the document" @@ -730,11 +730,11 @@ msgstr "<0>\"{0}\" is no longer available to sign" #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "<0>{organisationName} does not have an active subscription. Please contact the organisation administrator to renew their plan before accepting this invitation." -msgstr "<0>{organisationName} does not have an active subscription. Please contact the organisation administrator to renew their plan before accepting this invitation." +msgstr "<0>{organisationName} does not have an active subscription. Please contact the organization administrator to renew their plan before accepting this invitation." #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "<0>{organisationName} has reached its member limit. Please contact the organisation administrator to upgrade their plan before accepting this invitation." -msgstr "<0>{organisationName} has reached its member limit. Please contact the organisation administrator to upgrade their plan before accepting this invitation." +msgstr "<0>{organisationName} has reached its member limit. Please contact the organization administrator to upgrade their plan before accepting this invitation." #: packages/email/templates/organisation-account-link-confirmation.tsx msgid "<0>{organisationName} has requested to create an account on your behalf." @@ -742,7 +742,7 @@ msgstr "<0>{organisationName} has requested to create an account on your beh #: packages/email/templates/organisation-account-link-confirmation.tsx msgid "<0>{organisationName} has requested to link your current Documenso account to their organisation." -msgstr "<0>{organisationName} has requested to link your current Documenso account to their organisation." +msgstr "<0>{organisationName} has requested to link your current Documenso account to their organization." #: apps/remix/app/components/general/document-signing/document-signing-page-view-v1.tsx msgid "<0>{senderName} {senderEmail} has invited you to approve this document" @@ -853,7 +853,7 @@ msgstr "<0>Note - If you use Links in combination with direct templates, you #: packages/ui/components/template/template-type-select.tsx msgid "<0>Organisation templates are shared across all teams in your organisation but can only be edited by the owning team." -msgstr "<0>Organisation templates are shared across all teams in your organisation but can only be edited by the owning team." +msgstr "<0>Organization templates are shared across all teams in your organization but can only be edited by the owning team." #: packages/ui/components/template/template-type-select.tsx msgid "<0>Private templates can only be used by your team." @@ -891,11 +891,11 @@ msgstr "<0>Uploaded - A signature that is uploaded from a file." #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "0 Free organisations left" -msgstr "0 Free organisations left" +msgstr "0 Free organizations left" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "1 Free organisations left" -msgstr "1 Free organisations left" +msgstr "1 Free organizations left" #: apps/remix/app/components/dialogs/token-create-dialog.tsx msgid "1 month" @@ -953,12 +953,12 @@ msgstr "404 Not Found" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "404 Organisation group not found" -msgstr "404 Organisation group not found" +msgstr "404 Organization group not found" #: apps/remix/app/routes/_authenticated+/_layout.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "404 Organisation not found" -msgstr "404 Organisation not found" +msgstr "404 Organization not found" #: apps/remix/app/routes/_profile+/_layout.tsx msgid "404 Profile not found" @@ -1040,19 +1040,19 @@ msgstr "A means to print or download documents for your records" #: packages/email/templates/organisation-join.tsx msgid "A member has joined your organisation on Documenso" -msgstr "A member has joined your organisation on Documenso" +msgstr "A member has joined your organization on Documenso" #: packages/lib/jobs/definitions/emails/send-organisation-member-left-email.handler.ts msgid "A member has left your organisation" -msgstr "A member has left your organisation" +msgstr "A member has left your organization" #: packages/email/templates/organisation-leave.tsx msgid "A member has left your organisation {organisationName}" -msgstr "A member has left your organisation {organisationName}" +msgstr "A member has left your organization {organisationName}" #: packages/email/templates/organisation-leave.tsx msgid "A member has left your organisation on Documenso" -msgstr "A member has left your organisation on Documenso" +msgstr "A member has left your organization on Documenso" #: apps/remix/app/components/dialogs/token-create-dialog.tsx msgid "A name to help you identify this token later." @@ -1060,11 +1060,11 @@ msgstr "A name to help you identify this token later." #: packages/lib/jobs/definitions/emails/send-organisation-member-joined-email.handler.ts msgid "A new member has joined your organisation" -msgstr "A new member has joined your organisation" +msgstr "A new member has joined your organization" #: packages/email/templates/organisation-join.tsx msgid "A new member has joined your organisation {organisationName}" -msgstr "A new member has joined your organisation {organisationName}" +msgstr "A new member has joined your organization {organisationName}" #: apps/remix/app/components/forms/forgot-password.tsx #: apps/remix/app/routes/_unauthenticated+/check-email.tsx @@ -1119,11 +1119,11 @@ msgstr "A unique URL to access your profile" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "A unique URL to identify the organisation" -msgstr "A unique URL to identify the organisation" +msgstr "A unique URL to identify the organization" #: apps/remix/app/components/forms/organisation-update-form.tsx msgid "A unique URL to identify your organisation" -msgstr "A unique URL to identify your organisation" +msgstr "A unique URL to identify your organization" #: apps/remix/app/components/dialogs/team-create-dialog.tsx #: apps/remix/app/components/forms/team-update-form.tsx @@ -1151,7 +1151,7 @@ msgstr "Accept & Link Account" #: packages/email/templates/organisation-invite.tsx msgid "Accept invitation to join an organisation on Documenso" -msgstr "Accept invitation to join an organisation on Documenso" +msgstr "Accept invitation to join an organization on Documenso" #: packages/email/templates/confirm-team-email.tsx msgid "Accept team email request for {teamName} on Documenso" @@ -1232,7 +1232,7 @@ msgstr "Account unlinked" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Accounts are automatically added to your organisation on sign-in" -msgstr "Accounts are automatically added to your organisation on sign-in" +msgstr "Accounts are automatically added to your organization on sign-in" #: apps/remix/app/routes/_unauthenticated+/articles.signature-disclosure.tsx msgid "Acknowledgment" @@ -1321,7 +1321,7 @@ msgstr "Add 2 or more signers to enable signing order." #: apps/remix/app/components/dialogs/organisation-email-domain-create-dialog.tsx msgid "Add a custom domain to send emails on behalf of your organisation. We'll generate DKIM records that you need to add to your DNS provider." -msgstr "Add a custom domain to send emails on behalf of your organisation. We'll generate DKIM records that you need to add to your DNS provider." +msgstr "Add a custom domain to send emails on behalf of your organization. We'll generate DKIM records that you need to add to your DNS provider." #: packages/ui/primitives/document-dropzone.tsx msgid "Add a document" @@ -1362,11 +1362,11 @@ msgstr "Add an external ID to the template. This can be used to identify in exte #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "Add an optional reason for cancelling these documents" -msgstr "Add an optional reason for cancelling these documents" +msgstr "Add an optional reason for canceling these documents" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx msgid "Add an optional reason for cancelling this document" -msgstr "Add an optional reason for cancelling this document" +msgstr "Add an optional reason for canceling this document" #: apps/remix/app/components/general/envelope-editor/envelope-editor-upload-page.tsx msgid "Add and configure multiple documents" @@ -1460,7 +1460,7 @@ msgstr "Add Myself" #: apps/remix/app/components/dialogs/organisation-email-create-dialog.tsx msgid "Add Organisation Email" -msgstr "Add Organisation Email" +msgstr "Add Organization Email" #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx @@ -1609,7 +1609,7 @@ msgstr "AI Features" #: apps/remix/app/components/dialogs/ai-features-enable-dialog.tsx msgid "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." -msgstr "AI features are disabled for your team. Please ask your team owner or organisation owner to enable them." +msgstr "AI features are disabled for your team. Please ask your team owner or organization owner to enable them." #: apps/remix/app/components/general/app-command-menu.tsx #: apps/remix/app/components/general/document/document-status.tsx @@ -1691,7 +1691,7 @@ msgstr "All Time" #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "Allow all organisation members to access this team" -msgstr "Allow all organisation members to access this team" +msgstr "Allow all organization members to access this team" #: packages/email/templates/confirm-team-email.tsx msgid "Allow document recipients to reply directly to this email address" @@ -1699,7 +1699,7 @@ msgstr "Allow document recipients to reply directly to this email address" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Allow Personal Organisations" -msgstr "Allow Personal Organisations" +msgstr "Allow Personal Organizations" #: apps/remix/app/components/embed/authoring/configure-document-recipients.tsx #: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx @@ -1829,7 +1829,7 @@ msgstr "An error occurred while auto-signing the document, some fields may not b #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "An error occurred while cancelling the documents." -msgstr "An error occurred while cancelling the documents." +msgstr "An error occurred while canceling the documents." #: apps/remix/app/utils/toast-error-messages.ts msgid "An error occurred while creating document from template." @@ -1969,19 +1969,19 @@ msgstr "An error occurred. Please try again later." #: packages/lib/jobs/definitions/emails/send-organisation-limit-alert-email.handler.ts msgid "An organisation has exceeded their fair use limits" -msgstr "An organisation has exceeded their fair use limits" +msgstr "An organization has exceeded their fair use limits" #: packages/lib/jobs/definitions/emails/send-organisation-limit-alert-email.handler.ts msgid "An organisation is nearing their fair use limits" -msgstr "An organisation is nearing their fair use limits" +msgstr "An organization is nearing their fair use limits" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "An organisation wants to create an account for you. Please review the details below." -msgstr "An organisation wants to create an account for you. Please review the details below." +msgstr "An organization wants to create an account for you. Please review the details below." #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "An organisation wants to link your account. Please review the details below." -msgstr "An organisation wants to link your account. Please review the details below." +msgstr "An organization wants to link your account. Please review the details below." #: apps/remix/app/components/general/generic-error-layout.tsx msgid "An unexpected error occurred." @@ -2191,7 +2191,7 @@ msgstr "Are you sure you want to remove the <0>{passkeyName} passkey?" #: apps/remix/app/components/dialogs/organisation-delete-dialog.tsx msgid "Are you sure you wish to delete this organisation?" -msgstr "Are you sure you wish to delete this organisation?" +msgstr "Are you sure you wish to delete this organization?" #: apps/remix/app/components/dialogs/team-delete-dialog.tsx msgid "Are you sure you wish to delete this team?" @@ -2400,11 +2400,11 @@ msgstr "Banner Updated" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Base background colour." -msgstr "Base background colour." +msgstr "Base background color." #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Base text colour." -msgstr "Base text colour." +msgstr "Base text color." #: packages/email/template-components/template-confirmation-email.tsx msgid "Before you get started, please confirm your email address by clicking the button below:" @@ -2470,11 +2470,11 @@ msgstr "Brand accent" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Colours" -msgstr "Brand Colours" +msgstr "Brand Colors" #: apps/remix/app/components/dialogs/branding-preferences-reset-dialog.tsx msgid "Brand colours, including background, foreground, primary, and border colours" -msgstr "Brand colours, including background, foreground, primary, and border colours" +msgstr "Brand colors, including background, foreground, primary, and border colors" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Brand Details" @@ -2737,11 +2737,11 @@ msgstr "Cancel Documents" #: apps/remix/app/components/general/envelope-editor/envelope-editor-header.tsx #: packages/lib/constants/document.ts msgid "Cancelled" -msgstr "Cancelled" +msgstr "Canceled" #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "Cancelled by user" -msgstr "Cancelled by user" +msgstr "Canceled by user" #: apps/remix/app/components/embed/authoring/configure-document-upload.tsx msgid "Cannot remove document" @@ -2758,7 +2758,7 @@ msgstr "Cannot upload items after the document has been sent" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Capabilities enabled for this organisation." -msgstr "Capabilities enabled for this organisation." +msgstr "Capabilities enabled for this organization." #: packages/lib/constants/recipient-roles.ts msgctxt "Recipient role name" @@ -3210,7 +3210,7 @@ msgstr "Contact us" #: apps/remix/app/components/general/settings-upsell/settings-upsell-card.tsx msgid "Contact your organisation owner to upgrade plans." -msgstr "Contact your organisation owner to upgrade plans." +msgstr "Contact your organization owner to upgrade plans." #: apps/remix/app/components/general/admin-site-banner-section.tsx msgid "Content" @@ -3364,7 +3364,7 @@ msgstr "Copy Link" #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Copy organisation ID" -msgstr "Copy organisation ID" +msgstr "Copy organization ID" #: apps/remix/app/components/tables/settings-public-profile-templates-table.tsx msgid "Copy sharable link" @@ -3417,11 +3417,11 @@ msgstr "Create a new account" #. placeholder {0}: emailDomain.domain #: apps/remix/app/components/dialogs/organisation-email-create-dialog.tsx msgid "Create a new email address for your organisation using the domain <0>{0}." -msgstr "Create a new email address for your organisation using the domain <0>{0}." +msgstr "Create a new email address for your organization using the domain <0>{0}." #: apps/remix/app/components/general/billing-plans.tsx msgid "Create a new organisation with {planName} plan. Keep your current organisation on it's current plan" -msgstr "Create a new organisation with {planName} plan. Keep your current organisation on it's current plan" +msgstr "Create a new organization with {planName} plan. Keep your current organization on it's current plan" #: apps/remix/app/components/dialogs/admin-user-create-dialog.tsx msgid "Create a new user. A welcome email will be sent with a link to set their password." @@ -3447,15 +3447,15 @@ msgstr "Create account" #: apps/remix/app/components/dialogs/admin-organisation-create-dialog.tsx msgid "Create an organisation for this user" -msgstr "Create an organisation for this user" +msgstr "Create an organization for this user" #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Create an organisation to collaborate with teams" -msgstr "Create an organisation to collaborate with teams" +msgstr "Create an organization to collaborate with teams" #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Create an organisation to get started." -msgstr "Create an organisation to get started." +msgstr "Create an organization to get started." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.tokens.tsx msgid "Create and manage API tokens. See our <0>documentation for more information." @@ -3541,16 +3541,16 @@ msgstr "Create one automatically" #: apps/remix/app/components/general/settings-org-switcher.tsx #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "Create organisation" -msgstr "Create organisation" +msgstr "Create organization" #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "Create Organisation" -msgstr "Create Organisation" +msgstr "Create Organization" #: apps/remix/app/components/general/billing-plans.tsx msgid "Create separate organisation" -msgstr "Create separate organisation" +msgstr "Create separate organization" #: apps/remix/app/components/dialogs/template-use-dialog.tsx msgid "Create signing links" @@ -3667,7 +3667,7 @@ msgstr "Creating Template" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx msgid "CSS rules were dropped during sanitisation" -msgstr "CSS rules were dropped during sanitisation" +msgstr "CSS rules were dropped during sanitization" #: apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx msgid "CSV Structure" @@ -3691,11 +3691,11 @@ msgstr "Current recipients:" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Current usage against organisation limits." -msgstr "Current usage against organisation limits." +msgstr "Current usage against organization limits." #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "Currently all organisation members can access this team" -msgstr "Currently all organisation members can access this team" +msgstr "Currently all organization members can access this team" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.branding.tsx @@ -3721,7 +3721,7 @@ msgstr "Custom CSS" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Custom CSS is sanitised on save. Layout-breaking properties, remote URLs, and pseudo-elements are stripped automatically. Any rules dropped during sanitisation will be shown after you save." -msgstr "Custom CSS is sanitised on save. Layout-breaking properties, remote URLs, and pseudo-elements are stripped automatically. Any rules dropped during sanitisation will be shown after you save." +msgstr "Custom CSS is sanitized on save. Layout-breaking properties, remote URLs, and pseudo-elements are stripped automatically. Any rules dropped during sanitization will be shown after you save." #: packages/ui/components/document/expiration-period-picker.tsx msgid "Custom duration" @@ -3733,7 +3733,7 @@ msgstr "Custom interval" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups._index.tsx msgid "Custom Organisation Groups" -msgstr "Custom Organisation Groups" +msgstr "Custom Organization Groups" #: apps/remix/app/components/general/settings-org-switcher.tsx msgid "Custom Plan" @@ -3741,7 +3741,7 @@ msgstr "Custom Plan" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Customise the colours used on your signing pages." -msgstr "Customise the colours used on your signing pages." +msgstr "Customize the colors used on your signing pages." #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Danger Zone" @@ -3806,7 +3806,7 @@ msgstr "Default (system mailer)" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Default border colour." -msgstr "Default border colour." +msgstr "Default border color." #: apps/remix/app/components/dialogs/document-preferences-reset-dialog.tsx msgid "Default date format" @@ -3850,7 +3850,7 @@ msgstr "Default file" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Default Organisation Role for New Users" -msgstr "Default Organisation Role for New Users" +msgstr "Default Organization Role for New Users" #: apps/remix/app/components/dialogs/document-preferences-reset-dialog.tsx msgid "Default recipients" @@ -3862,11 +3862,11 @@ msgstr "Default Recipients" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Default settings applied to this organisation." -msgstr "Default settings applied to this organisation." +msgstr "Default settings applied to this organization." #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Default settings applied to this team. Inherited values come from the organisation." -msgstr "Default settings applied to this team. Inherited values come from the organisation." +msgstr "Default settings applied to this team. Inherited values come from the organization." #: apps/remix/app/components/dialogs/document-preferences-reset-dialog.tsx msgid "Default signature settings" @@ -4030,15 +4030,15 @@ msgstr "Delete Folder" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.general.tsx msgid "Delete organisation" -msgstr "Delete organisation" +msgstr "Delete organization" #: apps/remix/app/components/dialogs/organisation-group-delete-dialog.tsx msgid "Delete organisation group" -msgstr "Delete organisation group" +msgstr "Delete organization group" #: apps/remix/app/components/dialogs/organisation-member-delete-dialog.tsx msgid "Delete organisation member" -msgstr "Delete organisation member" +msgstr "Delete organization member" #: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx msgid "Delete passkey" @@ -4343,7 +4343,7 @@ msgstr "Document \"{0}\" - Rejection Confirmed" #. placeholder {0}: envelope.title #: packages/lib/jobs/definitions/emails/send-document-cancelled-emails.handler.ts msgid "Document \"{0}\" Cancelled" -msgstr "Document \"{0}\" Cancelled" +msgstr "Document \"{0}\" Canceled" #: packages/ui/primitives/document-upload-button.tsx msgid "Document (Legacy)" @@ -4385,19 +4385,19 @@ msgstr "Document Approved" #: apps/remix/app/components/general/document/document-status.tsx #: apps/remix/app/utils/toast-error-messages.ts msgid "Document cancelled" -msgstr "Document cancelled" +msgstr "Document canceled" #: packages/lib/utils/document-audit-logs.ts msgctxt "Audit log format" msgid "Document cancelled" -msgstr "Document cancelled" +msgstr "Document canceled" #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: packages/lib/jobs/definitions/emails/send-document-deleted-emails.handler.ts #: packages/lib/server-only/admin/admin-super-delete-document.ts msgid "Document Cancelled" -msgstr "Document Cancelled" +msgstr "Document Canceled" #: apps/remix/app/components/general/admin-global-settings-section.tsx #: apps/remix/app/components/general/document/document-status.tsx @@ -4640,7 +4640,7 @@ msgstr "Document signing auth updated" #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "Document signing process will be cancelled" -msgstr "Document signing process will be cancelled" +msgstr "Document signing process will be canceled" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id.logs.tsx msgid "Document status" @@ -4758,7 +4758,7 @@ msgstr "Documents and resources related to this envelope." #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "Documents cancelled" -msgstr "Documents cancelled" +msgstr "Documents canceled" #: apps/remix/app/components/tables/organisation-insights-table.tsx #: apps/remix/app/components/tables/organisation-insights-table.tsx @@ -4783,7 +4783,7 @@ msgstr "Documents downloaded" #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "Documents partially cancelled" -msgstr "Documents partially cancelled" +msgstr "Documents partially canceled" #: apps/remix/app/components/dialogs/envelopes-bulk-delete-dialog.tsx msgid "Documents partially deleted" @@ -5268,7 +5268,7 @@ msgstr "Email Settings" #: apps/remix/app/components/dialogs/admin-organisation-delete-dialog.tsx msgid "Email the organisation owner to notify them of the deletion." -msgstr "Email the organisation owner to notify them of the deletion." +msgstr "Email the organization owner to notify them of the deletion." #: packages/ui/components/document/document-email-checkboxes.tsx msgid "Email the owner when a document is created from a direct template" @@ -5379,7 +5379,7 @@ msgstr "Enable Custom Branding" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Enable custom branding for all documents in this organisation" -msgstr "Enable custom branding for all documents in this organisation" +msgstr "Enable custom branding for all documents in this organization" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Enable custom branding for all documents in this team" @@ -5459,7 +5459,7 @@ msgstr "Enter a max request count greater than 0" #: apps/remix/app/components/dialogs/folder-create-dialog.tsx msgid "Enter a name for your new folder. Folders help you organise your items." -msgstr "Enter a name for your new folder. Folders help you organise your items." +msgstr "Enter a name for your new folder. Folders help you organize your items." #: apps/remix/app/components/dialogs/envelope-rename-dialog.tsx msgid "Enter a new title" @@ -5944,7 +5944,7 @@ msgstr "Features" #: apps/remix/app/components/dialogs/admin-organisation-sync-subscription-dialog.tsx msgid "Fetch the latest subscription data from Stripe and apply it to this organisation." -msgstr "Fetch the latest subscription data from Stripe and apply it to this organisation." +msgstr "Fetch the latest subscription data from Stripe and apply it to this organization." #: packages/ui/primitives/document-flow/field-items-advanced-settings/text-field.tsx msgid "Field character limit" @@ -6032,7 +6032,7 @@ msgstr "Filter by status" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Focus ring colour." -msgstr "Focus ring colour." +msgstr "Focus ring color." #: apps/remix/app/components/dialogs/envelopes-bulk-move-dialog.tsx msgid "Folder" @@ -6088,7 +6088,7 @@ msgstr "For each recipient, provide their email (required) and name (optional) i #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "For example, if the claim has a new flag \"FLAG_1\" set to true, then this organisation will get that flag added." -msgstr "For example, if the claim has a new flag \"FLAG_1\" set to true, then this organisation will get that flag added." +msgstr "For example, if the claim has a new flag \"FLAG_1\" set to true, then this organization will get that flag added." #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Foreground" @@ -6347,11 +6347,11 @@ msgstr "Help the AI assign fields to the right recipients." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.email-domains._index.tsx msgid "Here you can add email domains to your organisation." -msgstr "Here you can add email domains to your organisation." +msgstr "Here you can add email domains to your organization." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.general.tsx msgid "Here you can edit your organisation details." -msgstr "Here you can edit your organisation details." +msgstr "Here you can edit your organization details." #: apps/remix/app/routes/_authenticated+/settings+/profile.tsx msgid "Here you can edit your personal details." @@ -6367,7 +6367,7 @@ msgstr "Here you can manage your password and security settings." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx msgid "Here you can set branding preferences for your organisation. Teams will inherit these settings by default." -msgstr "Here you can set branding preferences for your organisation. Teams will inherit these settings by default." +msgstr "Here you can set branding preferences for your organization. Teams will inherit these settings by default." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.branding.tsx msgid "Here you can set branding preferences for your team." @@ -6375,7 +6375,7 @@ msgstr "Here you can set branding preferences for your team." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.certificates.tsx msgid "Here you can set certificate and audit log preferences for your organisation. Teams will inherit these settings by default." -msgstr "Here you can set certificate and audit log preferences for your organisation. Teams will inherit these settings by default." +msgstr "Here you can set certificate and audit log preferences for your organization. Teams will inherit these settings by default." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.certificates.tsx msgid "Here you can set certificate and audit log preferences for your team." @@ -6383,11 +6383,11 @@ msgstr "Here you can set certificate and audit log preferences for your team." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.document.tsx msgid "Here you can set document preferences for your organisation. Teams will inherit these settings by default." -msgstr "Here you can set document preferences for your organisation. Teams will inherit these settings by default." +msgstr "Here you can set document preferences for your organization. Teams will inherit these settings by default." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.reminders.tsx msgid "Here you can set expiration and signing reminder preferences for your organisation. Teams will inherit these settings by default." -msgstr "Here you can set expiration and signing reminder preferences for your organisation. Teams will inherit these settings by default." +msgstr "Here you can set expiration and signing reminder preferences for your organization. Teams will inherit these settings by default." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.reminders.tsx msgid "Here you can set expiration and signing reminder preferences for your team." @@ -6502,7 +6502,7 @@ msgstr "I am the owner of this document" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "I understand that I am providing my credentials to a 3rd party service configured by this organisation" -msgstr "I understand that I am providing my credentials to a 3rd party service configured by this organisation" +msgstr "I understand that I am providing my credentials to a 3rd party service configured by this organization" #: apps/remix/app/components/tables/admin-claims-table.tsx #: apps/remix/app/components/tables/admin-dashboard-users-table.tsx @@ -6641,11 +6641,11 @@ msgstr "Inherit authentication method" #: apps/remix/app/components/forms/reminder-preferences-form.tsx #: apps/remix/app/components/forms/reminder-preferences-form.tsx msgid "Inherit from organisation" -msgstr "Inherit from organisation" +msgstr "Inherit from organization" #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "Inherit organisation members" -msgstr "Inherit organisation members" +msgstr "Inherit organization members" #: apps/remix/app/components/forms/inheritable-field.tsx #: apps/remix/app/components/general/admin-global-settings-section.tsx @@ -6775,7 +6775,7 @@ msgstr "Invite Members" #: apps/remix/app/components/dialogs/organisation-member-invite-dialog.tsx #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "Invite organisation members" -msgstr "Invite organisation members" +msgstr "Invite organization members" #: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx msgid "Invite team members to collaborate" @@ -6783,7 +6783,7 @@ msgstr "Invite team members to collaborate" #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "Invite them to the organisation first" -msgstr "Invite them to the organisation first" +msgstr "Invite them to the organization first" #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Invited" @@ -6810,7 +6810,7 @@ msgstr "IP Address" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Irreversible actions for this organisation" -msgstr "Irreversible actions for this organisation" +msgstr "Irreversible actions for this organization" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Issuer URL" @@ -6997,7 +6997,7 @@ msgstr "Leave" #: apps/remix/app/components/forms/branding-preferences-form.tsx #: apps/remix/app/components/forms/email-preferences-form.tsx msgid "Leave blank to inherit from the organisation." -msgstr "Leave blank to inherit from the organisation." +msgstr "Leave blank to inherit from the organization." #: apps/remix/app/components/forms/email-transport-form.tsx msgid "Leave blank to keep current" @@ -7005,7 +7005,7 @@ msgstr "Leave blank to keep current" #: apps/remix/app/components/dialogs/organisation-leave-dialog.tsx msgid "Leave organisation" -msgstr "Leave organisation" +msgstr "Leave organization" #: apps/remix/app/components/forms/editor/editor-field-generic-field-forms.tsx msgid "Left" @@ -7172,7 +7172,7 @@ msgstr "Manage {0}'s profile" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Manage a custom SSO login portal for your organisation." -msgstr "Manage a custom SSO login portal for your organisation." +msgstr "Manage a custom SSO login portal for your organization." #: apps/remix/app/routes/_authenticated+/admin+/email-transports._index.tsx msgid "Manage all email transports" @@ -7180,7 +7180,7 @@ msgstr "Manage all email transports" #: apps/remix/app/routes/_authenticated+/settings+/organisations.tsx msgid "Manage all organisations you are currently associated with." -msgstr "Manage all organisations you are currently associated with." +msgstr "Manage all organizations you are currently associated with." #: apps/remix/app/routes/_authenticated+/admin+/claims.tsx msgid "Manage all subscription claims" @@ -7202,7 +7202,7 @@ msgstr "Manage Billing" #: apps/remix/app/routes/_authenticated+/settings+/billing.tsx msgid "Manage billing and subscriptions for organisations where you have billing management permissions." -msgstr "Manage billing and subscriptions for organisations where you have billing management permissions." +msgstr "Manage billing and subscriptions for organizations where you have billing management permissions." #: apps/remix/app/components/dialogs/public-profile-template-manage-dialog.tsx msgid "Manage details for this public template" @@ -7224,15 +7224,15 @@ msgstr "Manage linked accounts" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Manage organisation" -msgstr "Manage organisation" +msgstr "Manage organization" #: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx msgid "Manage Organisation" -msgstr "Manage Organisation" +msgstr "Manage Organization" #: apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx msgid "Manage organisations" -msgstr "Manage organisations" +msgstr "Manage organizations" #: apps/remix/app/routes/_authenticated+/settings+/security._index.tsx #: apps/remix/app/routes/_authenticated+/settings+/security.passkeys.tsx @@ -7259,12 +7259,12 @@ msgstr "Manage team" #. placeholder {0}: organisation.name #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Manage the {0} organisation" -msgstr "Manage the {0} organisation" +msgstr "Manage the {0} organization" #. placeholder {0}: organisation.name #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Manage the {0} organisation subscription" -msgstr "Manage the {0} organisation subscription" +msgstr "Manage the {0} organization subscription" #. placeholder {0}: team.name #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx @@ -7273,7 +7273,7 @@ msgstr "Manage the {0} team" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups._index.tsx msgid "Manage the custom groups of members for your organisation." -msgstr "Manage the custom groups of members for your organisation." +msgstr "Manage the custom groups of members for your organization." #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx msgid "Manage the direct link signing for this template" @@ -7297,7 +7297,7 @@ msgstr "Manage the settings for this folder." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.teams.tsx msgid "Manage the teams in this organisation." -msgstr "Manage the teams in this organisation." +msgstr "Manage the teams in this organization." #: apps/remix/app/routes/_authenticated+/admin+/users._index.tsx msgid "Manage users" @@ -7309,7 +7309,7 @@ msgstr "Manage your email domain settings." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Manage your organisation group settings." -msgstr "Manage your organisation group settings." +msgstr "Manage your organization group settings." #: apps/remix/app/routes/_authenticated+/settings+/security.passkeys.tsx msgid "Manage your passkeys." @@ -7400,7 +7400,7 @@ msgstr "Member Count" #: apps/remix/app/components/dialogs/admin-organisation-member-delete-dialog.tsx msgid "Member has been removed from the organisation." -msgstr "Member has been removed from the organisation." +msgstr "Member has been removed from the organization." #: apps/remix/app/components/dialogs/admin-team-member-delete-dialog.tsx msgid "Member has been removed from the team." @@ -7525,7 +7525,7 @@ msgstr "Move Templates to Folder" #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx msgid "Move the subscription from \"{sourceOrganisationName}\" to another organisation owned by this user." -msgstr "Move the subscription from \"{sourceOrganisationName}\" to another organisation owned by this user." +msgstr "Move the subscription from \"{sourceOrganisationName}\" to another organization owned by this user." #: apps/remix/app/components/tables/documents-table-action-dropdown.tsx #: apps/remix/app/components/tables/templates-table-action-dropdown.tsx @@ -7701,7 +7701,7 @@ msgstr "No documents found" #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx msgid "No eligible organisations found. The target must be on the free plan." -msgstr "No eligible organisations found. The target must be on the free plan." +msgstr "No eligible organizations found. The target must be on the free plan." #: apps/remix/app/components/dialogs/ai-recipient-detection-dialog.tsx msgid "No email detected" @@ -7768,15 +7768,15 @@ msgstr "No members selected" #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "No organisation members available" -msgstr "No organisation members available" +msgstr "No organization members available" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates._index.tsx msgid "No organisation templates are shared with your team yet." -msgstr "No organisation templates are shared with your team yet." +msgstr "No organization templates are shared with your team yet." #: apps/remix/app/routes/_authenticated+/dashboard.tsx msgid "No organisations found" -msgstr "No organisations found" +msgstr "No organizations found" #: apps/remix/app/components/tables/settings-public-profile-templates-table.tsx msgid "No public profile templates found" @@ -7922,7 +7922,7 @@ msgstr "Not supported" #: apps/remix/app/components/tables/documents-table-empty-state.tsx msgid "Nothing cancelled" -msgstr "Nothing cancelled" +msgstr "Nothing canceled" #: apps/remix/app/components/tables/documents-table-empty-state.tsx #: apps/remix/app/components/tables/documents-table-empty-state.tsx @@ -8036,7 +8036,7 @@ msgstr "Only PDF files are allowed" #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "Only pending documents you have permission to manage will be cancelled." -msgstr "Only pending documents you have permission to manage will be cancelled." +msgstr "Only pending documents you have permission to manage will be canceled." #: apps/remix/app/components/general/generic-error-layout.tsx #: apps/remix/app/components/general/generic-error-layout.tsx @@ -8102,69 +8102,69 @@ msgstr "Or continue with" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx #: packages/ui/components/template/template-type-select.tsx msgid "Organisation" -msgstr "Organisation" +msgstr "Organization" #: packages/lib/server-only/organisation/delete-organisation-email.ts msgid "Organisation \"{organisationName}\" has been deleted" -msgstr "Organisation \"{organisationName}\" has been deleted" +msgstr "Organization \"{organisationName}\" has been deleted" #: packages/lib/constants/organisations-translations.ts msgid "Organisation Admin" -msgstr "Organisation Admin" +msgstr "Organization Admin" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation authentication portal URL" -msgstr "Organisation authentication portal URL" +msgstr "Organization authentication portal URL" #: apps/remix/app/components/dialogs/admin-organisation-create-dialog.tsx msgid "Organisation created" -msgstr "Organisation created" +msgstr "Organization created" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Organisation group not found" -msgstr "Organisation group not found" +msgstr "Organization group not found" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Organisation Group Settings" -msgstr "Organisation Group Settings" +msgstr "Organization Group Settings" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation has been updated successfully" -msgstr "Organisation has been updated successfully" +msgstr "Organization has been updated successfully" #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Organisation ID" -msgstr "Organisation ID" +msgstr "Organization ID" #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisation-insights._index.tsx msgid "Organisation Insights" -msgstr "Organisation Insights" +msgstr "Organization Insights" #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "Organisation invitation" -msgstr "Organisation invitation" +msgstr "Organization invitation" #: apps/remix/app/components/dialogs/organisation-member-invite-dialog.tsx msgid "Organisation invitations have been sent." -msgstr "Organisation invitations have been sent." +msgstr "Organization invitations have been sent." #: packages/lib/constants/organisations-translations.ts msgid "Organisation Manager" -msgstr "Organisation Manager" +msgstr "Organization Manager" #: apps/remix/app/components/tables/organisation-member-invites-table.tsx #: apps/remix/app/components/tables/organisation-members-table.tsx #: packages/lib/constants/organisations-translations.ts msgid "Organisation Member" -msgstr "Organisation Member" +msgstr "Organization Member" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.members.tsx msgid "Organisation Members" -msgstr "Organisation Members" +msgstr "Organization Members" #: apps/remix/app/components/dialogs/admin-organisation-create-dialog.tsx #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx @@ -8172,70 +8172,70 @@ msgstr "Organisation Members" #: apps/remix/app/components/general/billing-plans.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation Name" -msgstr "Organisation Name" +msgstr "Organization Name" #: apps/remix/app/routes/_authenticated+/_layout.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation not found" -msgstr "Organisation not found" +msgstr "Organization not found" #: packages/email/templates/organisation-limit-alert.tsx #: packages/email/templates/organisation-limit-alert.tsx #: packages/lib/jobs/definitions/emails/send-organisation-limit-alert-email.handler.ts msgid "Organisation Review Required" -msgstr "Organisation Review Required" +msgstr "Organization Review Required" #: apps/remix/app/components/dialogs/organisation-group-create-dialog.tsx #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Organisation role" -msgstr "Organisation role" +msgstr "Organization role" #: apps/remix/app/components/dialogs/organisation-member-invite-dialog.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Organisation Role" -msgstr "Organisation Role" +msgstr "Organization Role" #: apps/remix/app/components/general/settings-scope-breadcrumb.tsx #: apps/remix/app/components/general/unified-settings-sidebar.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings._layout.tsx msgid "Organisation Settings" -msgstr "Organisation Settings" +msgstr "Organization Settings" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Organisation SSO Portal" -msgstr "Organisation SSO Portal" +msgstr "Organization SSO Portal" #: apps/remix/app/routes/_authenticated+/admin+/_layout.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisation-stats._index.tsx msgid "Organisation Stats" -msgstr "Organisation Stats" +msgstr "Organization Stats" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation Teams" -msgstr "Organisation Teams" +msgstr "Organization Teams" #: apps/remix/app/components/general/envelope-editor/envelope-editor-header.tsx msgid "Organisation Template" -msgstr "Organisation Template" +msgstr "Organization Template" #: apps/remix/app/components/tables/templates-table.tsx msgid "Organisation templates are shared across all teams within the same organisation. Only the owning team can edit them." -msgstr "Organisation templates are shared across all teams within the same organisation. Only the owning team can edit them." +msgstr "Organization templates are shared across all teams within the same organization. Only the owning team can edit them." #: apps/remix/app/components/forms/organisation-update-form.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation URL" -msgstr "Organisation URL" +msgstr "Organization URL" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisation usage" -msgstr "Organisation usage" +msgstr "Organization usage" #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Organisation-level pending invites for this team's parent organisation." -msgstr "Organisation-level pending invites for this team's parent organisation." +msgstr "Organization-level pending invites for this team's parent organization." #: apps/remix/app/components/general/org-menu-switcher.tsx #: apps/remix/app/components/general/use-admin-search-categories.ts @@ -8244,27 +8244,27 @@ msgstr "Organisation-level pending invites for this team's parent organisation." #: apps/remix/app/routes/_authenticated+/settings+/organisations.tsx #: packages/lib/utils/settings-nav.ts msgid "Organisations" -msgstr "Organisations" +msgstr "Organizations" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "Organisations that the user is a member of." -msgstr "Organisations that the user is a member of." +msgstr "Organizations that the user is a member of." #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Organisations without a transport use the system default mailer." -msgstr "Organisations without a transport use the system default mailer." +msgstr "Organizations without a transport use the system default mailer." #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Organise your documents" -msgstr "Organise your documents" +msgstr "Organize your documents" #: apps/remix/app/components/dialogs/organisation-group-create-dialog.tsx msgid "Organise your members into groups which can be assigned to teams" -msgstr "Organise your members into groups which can be assigned to teams" +msgstr "Organize your members into groups which can be assigned to teams" #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Organise your templates" -msgstr "Organise your templates" +msgstr "Organize your templates" #: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx msgid "Organize your documents and templates" @@ -8293,7 +8293,7 @@ msgstr "Override" #: apps/remix/app/components/forms/document-preferences-form.tsx #: apps/remix/app/components/forms/email-preferences-form.tsx msgid "Override organisation settings" -msgstr "Override organisation settings" +msgstr "Override organization settings" #: apps/remix/app/components/dialogs/admin-organisation-member-update-dialog.tsx #: apps/remix/app/components/dialogs/admin-organisation-member-update-dialog.tsx @@ -8361,7 +8361,7 @@ msgstr "Passkey already exists for the provided authenticator" #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "Passkey creation cancelled due to one of the following reasons:" -msgstr "Passkey creation cancelled due to one of the following reasons:" +msgstr "Passkey creation canceled due to one of the following reasons:" #: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx msgid "Passkey has been removed" @@ -8482,7 +8482,7 @@ msgstr "Pending Documents" #: apps/remix/app/components/dialogs/envelopes-bulk-delete-dialog.tsx msgid "Pending documents will have their signing process cancelled" -msgstr "Pending documents will have their signing process cancelled" +msgstr "Pending documents will have their signing process canceled" #: apps/remix/app/components/general/organisations/organisation-invitations.tsx msgid "Pending invitations" @@ -8490,7 +8490,7 @@ msgstr "Pending invitations" #: apps/remix/app/routes/_authenticated+/admin+/teams.$id.tsx msgid "Pending Organisation Invites" -msgstr "Pending Organisation Invites" +msgstr "Pending Organization Invites" #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx msgid "Pending since" @@ -8498,7 +8498,7 @@ msgstr "Pending since" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "People with access to this organisation." -msgstr "People with access to this organisation." +msgstr "People with access to this organization." #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx #: apps/remix/app/components/general/billing-plans.tsx @@ -8518,7 +8518,7 @@ msgstr "Period" #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Permanently delete this organisation. Documents will be orphaned (not deleted) so they remain accessible via the deleted-account service account." -msgstr "Permanently delete this organisation. Documents will be orphaned (not deleted) so they remain accessible via the deleted-account service account." +msgstr "Permanently delete this organization. Documents will be orphaned (not deleted) so they remain accessible via the deleted-account service account." #: apps/remix/app/components/general/org-menu-switcher.tsx msgid "Personal Account" @@ -8645,7 +8645,7 @@ msgstr "Please contact the site owner for further assistance." #: apps/remix/app/components/general/document-signing/csc-recipient-signing-in-progress-page.tsx msgid "Please don't close this tab. The signing provider is finalising your signature." -msgstr "Please don't close this tab. The signing provider is finalising your signature." +msgstr "Please don't close this tab. The signing provider is finalizing your signature." #: apps/remix/app/components/dialogs/sign-field-number-dialog.tsx msgid "Please enter a number" @@ -8681,7 +8681,7 @@ msgstr "Please mark as viewed to complete." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Please note that anyone who signs in through your portal will be added to your organisation as a member." -msgstr "Please note that anyone who signs in through your portal will be added to your organisation as a member." +msgstr "Please note that anyone who signs in through your portal will be added to your organization as a member." #: apps/remix/app/components/dialogs/template-direct-link-dialog.tsx msgid "Please note that proceeding will remove direct linking recipient and turn it into a placeholder." @@ -8854,7 +8854,7 @@ msgstr "Primary" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Primary action colour." -msgstr "Primary action colour." +msgstr "Primary action color." #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Primary Foreground" @@ -9040,7 +9040,7 @@ msgstr "Reauthentication is required to sign this field" #: apps/remix/app/components/general/document-signing/csc-recipient-signing-in-progress-page.tsx msgid "Reauthorise and retry" -msgstr "Reauthorise and retry" +msgstr "Reauthorize and retry" #: packages/ui/components/recipient/recipient-role-select.tsx msgid "Receives copy" @@ -9089,7 +9089,7 @@ msgstr "Recipient authenticated with the signing provider" #: packages/lib/utils/document-audit-logs.ts msgid "Recipient authorised the remote signature" -msgstr "Recipient authorised the remote signature" +msgstr "Recipient authorized the remote signature" #: packages/lib/utils/document-audit-logs.ts msgid "Recipient CC'd the document" @@ -9217,7 +9217,7 @@ msgstr "Recipients will be able to sign the document once sent" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "Recipients will be notified that the document was cancelled" -msgstr "Recipients will be notified that the document was cancelled" +msgstr "Recipients will be notified that the document was canceled" #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "Recipients will still retain their copy of the document" @@ -9403,15 +9403,15 @@ msgstr "Remove member" #: apps/remix/app/components/tables/organisation-groups-table.tsx #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Remove organisation group" -msgstr "Remove organisation group" +msgstr "Remove organization group" #: apps/remix/app/components/tables/organisation-members-table.tsx msgid "Remove organisation member" -msgstr "Remove organisation member" +msgstr "Remove organization member" #: apps/remix/app/components/dialogs/admin-organisation-member-delete-dialog.tsx msgid "Remove Organisation Member" -msgstr "Remove Organisation Member" +msgstr "Remove Organization Member" #: apps/remix/app/components/general/rate-limit-array-input.tsx msgid "Remove rate limit" @@ -9492,7 +9492,7 @@ msgstr "Request" #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "Requesting Organisation" -msgstr "Requesting Organisation" +msgstr "Requesting Organization" #: packages/lib/constants/document-auth.ts msgid "Require 2FA" @@ -9801,7 +9801,7 @@ msgstr "Search" #: apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx msgid "Search and manage all organisations" -msgstr "Search and manage all organisations" +msgstr "Search and manage all organizations" #: apps/remix/app/routes/_authenticated+/admin+/claims.tsx msgid "Search by claim ID or name" @@ -9813,7 +9813,7 @@ msgstr "Search by document title, recipient:123, team:123 or user:123" #: apps/remix/app/routes/_authenticated+/admin+/email-domains._index.tsx msgid "Search by domain or organisation name" -msgstr "Search by domain or organisation name" +msgstr "Search by domain or organization name" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.webhooks.$id._index.tsx msgid "Search by ID" @@ -9829,19 +9829,19 @@ msgstr "Search by name or from address" #: apps/remix/app/routes/_authenticated+/admin+/organisations._index.tsx msgid "Search by organisation ID, name, customer ID or owner email" -msgstr "Search by organisation ID, name, customer ID or owner email" +msgstr "Search by organization ID, name, customer ID or owner email" #: apps/remix/app/components/tables/admin-organisation-overview-table.tsx msgid "Search by organisation name" -msgstr "Search by organisation name" +msgstr "Search by organization name" #: apps/remix/app/routes/_authenticated+/admin+/organisation-stats._index.tsx msgid "Search by organisation name, URL or ID" -msgstr "Search by organisation name, URL or ID" +msgstr "Search by organization name, URL or ID" #: apps/remix/app/components/general/app-command-menu.tsx msgid "Search documents, users, organisations…" -msgstr "Search documents, users, organisations…" +msgstr "Search documents, users, organizations…" #: apps/remix/app/components/general/document/document-search.tsx msgid "Search documents..." @@ -9876,7 +9876,7 @@ msgstr "Search members..." #: apps/remix/app/components/general/settings-org-switcher.tsx msgid "Search organisations…" -msgstr "Search organisations…" +msgstr "Search organizations…" #: apps/remix/app/components/general/settings-team-switcher.tsx msgid "Search teams…" @@ -9977,11 +9977,11 @@ msgstr "Select an option" #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx msgid "Select an organisation" -msgstr "Select an organisation" +msgstr "Select an organization" #: apps/remix/app/components/general/org-menu-switcher.tsx msgid "Select an organisation to view teams" -msgstr "Select an organisation to view teams" +msgstr "Select an organization to view teams" #: apps/remix/app/components/forms/editor/editor-field-checkbox-form.tsx #: packages/ui/primitives/document-flow/field-items-advanced-settings/checkbox-field.tsx @@ -11105,7 +11105,7 @@ msgstr "System Theme" #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx msgid "Target Organisation" -msgstr "Target Organisation" +msgstr "Target Organization" #: apps/remix/app/components/general/unified-settings-sidebar-mobile.tsx #: apps/remix/app/components/general/unified-settings-sidebar-mobile.tsx @@ -11277,15 +11277,15 @@ msgstr "Teams" #: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx msgid "Teams help you organise your work and collaborate with others. Create your first team to get started." -msgstr "Teams help you organise your work and collaborate with others. Create your first team to get started." +msgstr "Teams help you organize your work and collaborate with others. Create your first team to get started." #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "Teams that belong to this organisation." -msgstr "Teams that belong to this organisation." +msgstr "Teams that belong to this organization." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "Teams that this organisation group is currently assigned to" -msgstr "Teams that this organisation group is currently assigned to" +msgstr "Teams that this organization group is currently assigned to" #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "Teams that this user is a member of and their roles." @@ -11459,7 +11459,7 @@ msgstr "Text Color" #: apps/remix/app/components/forms/branding-preferences-form.tsx msgid "Text colour on primary buttons." -msgstr "Text colour on primary buttons." +msgstr "Text color on primary buttons." #: apps/remix/app/components/dialogs/sign-field-text-dialog.tsx msgid "Text is required" @@ -11608,7 +11608,7 @@ msgstr "The document will be immediately sent to recipients if this is checked." #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx msgid "The document will remain in your dashboard marked as Cancelled" -msgstr "The document will remain in your dashboard marked as Cancelled" +msgstr "The document will remain in your dashboard marked as Canceled" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._layout.tsx msgid "The document you are looking for could not be found." @@ -11625,7 +11625,7 @@ msgstr "The document's name" #: apps/remix/app/components/dialogs/envelopes-bulk-cancel-dialog.tsx msgid "The documents will remain in your dashboard marked as Cancelled" -msgstr "The documents will remain in your dashboard marked as Cancelled" +msgstr "The documents will remain in your dashboard marked as Canceled" #: apps/remix/app/components/forms/email-preferences-form.tsx msgid "The email address which will show up in the \"Reply To\" field in emails" @@ -11674,11 +11674,11 @@ msgstr "The following errors occurred:" #: packages/email/templates/organisation-delete.tsx msgid "The following organisation has been deleted by an administrator. You and your members will no longer be able to access this organisation, its teams, or its associated data." -msgstr "The following organisation has been deleted by an administrator. You and your members will no longer be able to access this organisation, its teams, or its associated data." +msgstr "The following organization has been deleted by an administrator. You and your members will no longer be able to access this organization, its teams, or its associated data." #: packages/email/templates/organisation-delete.tsx msgid "The following organisation has been deleted. You and your members will no longer be able to access this organisation, its teams, or its associated data." -msgstr "The following organisation has been deleted. You and your members will no longer be able to access this organisation, its teams, or its associated data." +msgstr "The following organization has been deleted. You and your members will no longer be able to access this organization, its teams, or its associated data." #: apps/remix/app/components/dialogs/envelope-distribute-dialog.tsx msgid "The following recipients require an email address:" @@ -11708,32 +11708,32 @@ msgstr "The OpenID discovery endpoint URL for your provider" #: apps/remix/app/routes/_unauthenticated+/o.$orgUrl.signin.tsx msgid "The organisation authentication portal does not exist, or is not configured" -msgstr "The organisation authentication portal does not exist, or is not configured" +msgstr "The organization authentication portal does not exist, or is not configured" #: apps/remix/app/components/dialogs/organisation-email-create-dialog.tsx msgid "The organisation email has been created successfully." -msgstr "The organisation email has been created successfully." +msgstr "The organization email has been created successfully." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "The organisation group you are looking for may have been removed, renamed or may have never existed." -msgstr "The organisation group you are looking for may have been removed, renamed or may have never existed." +msgstr "The organization group you are looking for may have been removed, renamed or may have never existed." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.groups.$id.tsx msgid "The organisation role that will be applied to all members in this group." -msgstr "The organisation role that will be applied to all members in this group." +msgstr "The organization role that will be applied to all members in this group." #: apps/remix/app/components/dialogs/admin-organisation-sync-subscription-dialog.tsx msgid "The organisation subscription has been synced with Stripe." -msgstr "The organisation subscription has been synced with Stripe." +msgstr "The organization subscription has been synced with Stripe." #: apps/remix/app/components/dialogs/admin-organisation-delete-dialog.tsx msgid "The organisation will be deleted in the background. Documents will be orphaned, not deleted." -msgstr "The organisation will be deleted in the background. Documents will be orphaned, not deleted." +msgstr "The organization will be deleted in the background. Documents will be orphaned, not deleted." #: apps/remix/app/routes/_authenticated+/_layout.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "The organisation you are looking for may have been removed, renamed or may have never existed." -msgstr "The organisation you are looking for may have been removed, renamed or may have never existed." +msgstr "The organization you are looking for may have been removed, renamed or may have never existed." #: apps/remix/app/components/general/generic-error-layout.tsx msgid "The page you are looking for was moved, removed, renamed or might never have existed." @@ -11941,7 +11941,7 @@ msgstr "There are no active drafts at the current moment. You can upload a docum #: apps/remix/app/components/tables/documents-table-empty-state.tsx msgid "There are no cancelled documents. Documents you cancel will remain here as a record that they were distributed." -msgstr "There are no cancelled documents. Documents you cancel will remain here as a record that they were distributed." +msgstr "There are no canceled documents. Documents you cancel will remain here as a record that they were distributed." #: apps/remix/app/components/tables/documents-table-empty-state.tsx msgid "There are no completed documents yet. Documents that you have created or received will appear here once completed." @@ -12034,7 +12034,7 @@ msgstr "This document cannot be changed" #: apps/remix/app/components/dialogs/envelope-cancel-dialog.tsx msgid "This document could not be cancelled at this time. Please try again." -msgstr "This document could not be cancelled at this time. Please try again." +msgstr "This document could not be canceled at this time. Please try again." #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "This document could not be deleted at this time. Please try again." @@ -12063,20 +12063,20 @@ msgstr "This document has already been sent to this recipient. You can no longer #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been cancelled" -msgstr "This document has been cancelled" +msgstr "This document has been canceled" #: apps/remix/app/routes/_recipient+/sign.$token+/complete.tsx msgid "This document has been cancelled by the owner and is no longer available for others to sign." -msgstr "This document has been cancelled by the owner and is no longer available for others to sign." +msgstr "This document has been canceled by the owner and is no longer available for others to sign." #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx #: apps/remix/app/routes/_recipient+/sign.$token+/_index.tsx msgid "This document has been cancelled by the owner." -msgstr "This document has been cancelled by the owner." +msgstr "This document has been canceled by the owner." #: apps/remix/app/utils/toast-error-messages.ts msgid "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." -msgstr "This document has been cancelled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." +msgstr "This document has been canceled by the sender and can no longer be signed. Please contact the sender if you believe this is a mistake." #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/documents.$id._index.tsx msgid "This document has been rejected by a recipient" @@ -12194,7 +12194,7 @@ msgstr "This is how the document will reach the recipients once the document is #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "This is the claim that this organisation was initially created with. Any feature flag changes to this claim will be backported into this organisation." -msgstr "This is the claim that this organisation was initially created with. Any feature flag changes to this claim will be backported into this organisation." +msgstr "This is the claim that this organization was initially created with. Any feature flag changes to this claim will be backported into this organization." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "This is the required scopes you must set in your provider's settings" @@ -12202,7 +12202,7 @@ msgstr "This is the required scopes you must set in your provider's settings" #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "This is the URL which users will use to sign in to your organisation." -msgstr "This is the URL which users will use to sign in to your organisation." +msgstr "This is the URL which users will use to sign in to your organization." #: apps/remix/app/components/dialogs/envelope-item-delete-dialog.tsx msgid "This item cannot be deleted" @@ -12218,15 +12218,15 @@ msgstr "This member is inherited from a group and cannot be removed from the tea #: apps/remix/app/components/general/organisations/organisation-billing-banner.tsx msgid "This organisation is awaiting payment. Complete checkout to unlock it." -msgstr "This organisation is awaiting payment. Complete checkout to unlock it." +msgstr "This organization is awaiting payment. Complete checkout to unlock it." #: apps/remix/app/routes/_unauthenticated+/organisation.sso.confirmation.$token.tsx msgid "This organisation will have administrative control over your account. You can revoke this access later, but they will retain access to any data they've already collected." -msgstr "This organisation will have administrative control over your account. You can revoke this access later, but they will retain access to any data they've already collected." +msgstr "This organization will have administrative control over your account. You can revoke this access later, but they will retain access to any data they've already collected." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.general.tsx msgid "This organisation, and any associated data will be permanently deleted." -msgstr "This organisation, and any associated data will be permanently deleted." +msgstr "This organization, and any associated data will be permanently deleted." #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "This passkey has already been registered." @@ -12298,7 +12298,7 @@ msgstr "This will be sent to the document owner when a recipient's signing windo #: apps/remix/app/components/tables/organisation-email-domains-table.tsx msgid "This will check and sync the status of all email domains for this organisation" -msgstr "This will check and sync the status of all email domains for this organisation" +msgstr "This will check and sync the status of all email domains for this organization" #. placeholder {0}: emailDomain.domain #: apps/remix/app/routes/_authenticated+/admin+/email-domains.$id.tsx @@ -12308,7 +12308,7 @@ msgstr "This will delete the existing SES identity for <0>{0} and recreate i #. placeholder {0}: selectedOrg.name #: apps/remix/app/components/dialogs/admin-swap-subscription-dialog.tsx msgid "This will move the subscription from \"{sourceOrganisationName}\" to \"{0}\". The source organisation will be reset to the free plan." -msgstr "This will move the subscription from \"{sourceOrganisationName}\" to \"{0}\". The source organisation will be reset to the free plan." +msgstr "This will move the subscription from \"{sourceOrganisationName}\" to \"{0}\". The source organization will be reset to the free plan." #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "This will ONLY backport feature flags which are set to true, anything disabled in the initial claim will not be backported" @@ -12371,11 +12371,11 @@ msgstr "To accept this invitation you must create an account." #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "To add members to this team, they must first be invited to the organisation. Only organisation admins and managers can invite new members — please contact one of them to invite members on your behalf." -msgstr "To add members to this team, they must first be invited to the organisation. Only organisation admins and managers can invite new members — please contact one of them to invite members on your behalf." +msgstr "To add members to this team, they must first be invited to the organization. Only organization admins and managers can invite new members — please contact one of them to invite members on your behalf." #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "To add members to this team, you must first add them to the organisation." -msgstr "To add members to this team, you must first add them to the organisation." +msgstr "To add members to this team, you must first add them to the organization." #. placeholder {0}: recipient.email #: apps/remix/app/components/general/document-signing/document-signing-auth-account.tsx @@ -12415,7 +12415,7 @@ msgstr "To assist with this field, you need to be logged in." #: apps/remix/app/components/dialogs/team-member-create-dialog.tsx msgid "To be able to add members to a team, you must first add them to the organisation. For more information, please see the <0>documentation." -msgstr "To be able to add members to a team, you must first add them to the organisation. For more information, please see the <0>documentation." +msgstr "To be able to add members to a team, you must first add them to the organization. For more information, please see the <0>documentation." #: apps/remix/app/components/dialogs/team-email-update-dialog.tsx msgid "To change the email you must remove and add a new email address." @@ -12721,7 +12721,7 @@ msgstr "Unable to disable two-factor authentication" #: apps/remix/app/components/general/organisations/organisation-invitations.tsx msgid "Unable to join this organisation at this time." -msgstr "Unable to join this organisation at this time." +msgstr "Unable to join this organization at this time." #: apps/remix/app/components/general/document/document-page-view-recent-activity.tsx msgid "Unable to load document history" @@ -12835,7 +12835,7 @@ msgstr "Unlock Email Domains" #: apps/remix/app/components/general/settings-upsell/sso-portal-upsell.tsx msgid "Unlock the Organisation SSO Portal" -msgstr "Unlock the Organisation SSO Portal" +msgstr "Unlock the Organization SSO Portal" #: apps/remix/app/components/general/folder/folder-card.tsx msgid "Unpin" @@ -12900,7 +12900,7 @@ msgstr "Update Claim" #: apps/remix/app/components/general/billing-plans.tsx msgid "Update current organisation" -msgstr "Update current organisation" +msgstr "Update current organization" #: apps/remix/app/components/general/envelope-editor/envelope-editor-header.tsx msgid "Update Document" @@ -12918,7 +12918,7 @@ msgstr "Update Fields" #: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx #: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx msgid "Update organisation member" -msgstr "Update organisation member" +msgstr "Update organization member" #: apps/remix/app/components/tables/settings-security-passkey-table-actions.tsx msgid "Update passkey" @@ -13202,7 +13202,7 @@ msgstr "User not found." #: apps/remix/app/routes/_authenticated+/admin+/users.$id.tsx msgid "User Organisations" -msgstr "User Organisations" +msgstr "User Organizations" #: apps/remix/app/components/forms/signup.tsx msgid "User profiles are here!" @@ -13429,7 +13429,7 @@ msgstr "View next document" #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/templates.$id._index.tsx msgid "View organisation template" -msgstr "View organisation template" +msgstr "View organization template" #: apps/remix/app/components/tables/admin-organisations-table.tsx msgid "View owner" @@ -13454,7 +13454,7 @@ msgstr "View the DNS records for this email domain" #: apps/remix/app/routes/_authenticated+/admin+/organisation-stats._index.tsx msgid "View, sort and filter monthly usage stats across organisations" -msgstr "View, sort and filter monthly usage stats across organisations" +msgstr "View, sort and filter monthly usage stats across organizations" #: apps/remix/app/components/embed/multisign/multi-sign-document-list.tsx #: apps/remix/app/components/general/document/document-page-view-recipients.tsx @@ -13578,7 +13578,7 @@ msgstr "We couldn't update the group. Please try again." #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx #: apps/remix/app/routes/_authenticated+/admin+/organisations.$id.tsx msgid "We couldn't update the organisation. Please try again." -msgstr "We couldn't update the organisation. Please try again." +msgstr "We couldn't update the organization. Please try again." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "We couldn't update the provider. Please try again." @@ -13586,7 +13586,7 @@ msgstr "We couldn't update the provider. Please try again." #: apps/remix/app/components/dialogs/admin-organisation-delete-dialog.tsx msgid "We encountered an error while attempting to delete this organisation. Please try again later." -msgstr "We encountered an error while attempting to delete this organisation. Please try again later." +msgstr "We encountered an error while attempting to delete this organization. Please try again later." #: packages/lib/client-only/providers/envelope-editor-provider.tsx #: packages/lib/client-only/providers/envelope-editor-provider.tsx @@ -13634,7 +13634,7 @@ msgstr "We encountered an unknown error while attempting to create a group. Plea #: apps/remix/app/components/dialogs/admin-organisation-create-dialog.tsx #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "We encountered an unknown error while attempting to create a organisation. Please try again later." -msgstr "We encountered an unknown error while attempting to create a organisation. Please try again later." +msgstr "We encountered an unknown error while attempting to create a organization. Please try again later." #: apps/remix/app/components/dialogs/team-create-dialog.tsx msgid "We encountered an unknown error while attempting to create a team. Please try again later." @@ -13646,7 +13646,7 @@ msgstr "We encountered an unknown error while attempting to delete it. Please tr #: apps/remix/app/components/dialogs/organisation-delete-dialog.tsx msgid "We encountered an unknown error while attempting to delete this organisation. Please try again later." -msgstr "We encountered an unknown error while attempting to delete this organisation. Please try again later." +msgstr "We encountered an unknown error while attempting to delete this organization. Please try again later." #: apps/remix/app/components/dialogs/team-delete-dialog.tsx msgid "We encountered an unknown error while attempting to delete this team. Please try again later." @@ -13674,11 +13674,11 @@ msgstr "We encountered an unknown error while attempting to enable access." #: apps/remix/app/components/dialogs/organisation-member-invite-dialog.tsx msgid "We encountered an unknown error while attempting to invite organisation members. Please try again later." -msgstr "We encountered an unknown error while attempting to invite organisation members. Please try again later." +msgstr "We encountered an unknown error while attempting to invite organization members. Please try again later." #: apps/remix/app/components/dialogs/organisation-leave-dialog.tsx msgid "We encountered an unknown error while attempting to leave this organisation. Please try again later." -msgstr "We encountered an unknown error while attempting to leave this organisation. Please try again later." +msgstr "We encountered an unknown error while attempting to leave this organization. Please try again later." #: apps/remix/app/components/dialogs/organisation-email-domain-delete-dialog.tsx msgid "We encountered an unknown error while attempting to remove this email domain. Please try again later." @@ -13751,7 +13751,7 @@ msgstr "We encountered an unknown error while attempting to update the template. #: apps/remix/app/components/dialogs/admin-organisation-member-update-dialog.tsx #: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx msgid "We encountered an unknown error while attempting to update this organisation member. Please try again later." -msgstr "We encountered an unknown error while attempting to update this organisation member. Please try again later." +msgstr "We encountered an unknown error while attempting to update this organization member. Please try again later." #: apps/remix/app/components/dialogs/team-group-update-dialog.tsx #: apps/remix/app/components/dialogs/team-member-update-dialog.tsx @@ -13760,7 +13760,7 @@ msgstr "We encountered an unknown error while attempting to update this team mem #: apps/remix/app/components/forms/organisation-update-form.tsx msgid "We encountered an unknown error while attempting to update your organisation. Please try again later." -msgstr "We encountered an unknown error while attempting to update your organisation. Please try again later." +msgstr "We encountered an unknown error while attempting to update your organization. Please try again later." #: apps/remix/app/components/forms/avatar-image.tsx #: apps/remix/app/components/forms/password.tsx @@ -13793,7 +13793,7 @@ msgstr "We need your signature to sign documents" #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "We were unable to add you to <0>{organisationName} at this time. Please try again later, or contact the organisation administrator." -msgstr "We were unable to add you to <0>{organisationName} at this time. Please try again later, or contact the organisation administrator." +msgstr "We were unable to add you to <0>{organisationName} at this time. Please try again later, or contact the organization administrator." #: apps/remix/app/components/forms/2fa/recovery-code-list.tsx msgid "We were unable to copy your recovery code to your clipboard. Please try again." @@ -14035,7 +14035,7 @@ msgstr "When enabled, signers can choose who should sign next in the sequence in #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "When enabled, users signing in via SSO for the first time will also receive their own personal organisation." -msgstr "When enabled, users signing in via SSO for the first time will also receive their own personal organisation." +msgstr "When enabled, users signing in via SSO for the first time will also receive their own personal organization." #: apps/remix/app/components/dialogs/passkey-create-dialog.tsx msgid "When you click continue, you will be prompted to add the first available authenticator on your system." @@ -14051,7 +14051,7 @@ msgstr "When you use our platform to affix your electronic signature to document #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.sso.tsx msgid "Whether to enable the SSO portal for your organisation" -msgstr "Whether to enable the SSO portal for your organisation" +msgstr "Whether to enable the SSO portal for your organization" #: apps/remix/app/routes/_profile+/p.$url.tsx msgid "While waiting for them to do so you can create your own Documenso account and get started with document signing right away." @@ -14144,7 +14144,7 @@ msgstr "You are about to delete <0>\"{title}\"" #. placeholder {0}: organisation.name #: apps/remix/app/components/dialogs/organisation-delete-dialog.tsx msgid "You are about to delete <0>{0}. All data related to this organisation such as teams, documents, and all other resources will be deleted. This action is irreversible." -msgstr "You are about to delete <0>{0}. All data related to this organisation such as teams, documents, and all other resources will be deleted. This action is irreversible." +msgstr "You are about to delete <0>{0}. All data related to this organization such as teams, documents, and all other resources will be deleted. This action is irreversible." #: apps/remix/app/components/dialogs/admin-organisation-delete-dialog.tsx msgid "You are about to delete <0>{organisationName}. This action is not reversible. All teams will be removed and all documents will be orphaned to the deleted-account service account." @@ -14156,7 +14156,7 @@ msgstr "You are about to delete the following team email from <0>{teamName}. #: apps/remix/app/components/dialogs/team-inherit-member-enable-dialog.tsx msgid "You are about to give all organisation members access to this team under their organisation role." -msgstr "You are about to give all organisation members access to this team under their organisation role." +msgstr "You are about to give all organization members access to this team under their organization role." #: apps/remix/app/components/dialogs/envelope-delete-dialog.tsx msgid "You are about to hide <0>\"{title}\"" @@ -14164,11 +14164,11 @@ msgstr "You are about to hide <0>\"{title}\"" #: apps/remix/app/components/dialogs/organisation-leave-dialog.tsx msgid "You are about to leave the following organisation." -msgstr "You are about to leave the following organisation." +msgstr "You are about to leave the following organization." #: apps/remix/app/components/dialogs/team-inherit-member-disable-dialog.tsx msgid "You are about to remove default access to this team for all organisation members. Any members not explicitly added to this team will no longer have access." -msgstr "You are about to remove default access to this team for all organisation members. Any members not explicitly added to this team will no longer have access." +msgstr "You are about to remove default access to this team for all organization members. Any members not explicitly added to this team will no longer have access." #: apps/remix/app/routes/_authenticated+/settings+/security.linked-accounts.tsx msgid "You are about to remove the <0>{provider} login method from your account." @@ -14211,7 +14211,7 @@ msgstr "You are about to remove the following user from <0>{teamName}." #: apps/remix/app/components/dialogs/admin-organisation-member-delete-dialog.tsx msgid "You are about to remove the following user from the organisation <0>{organisationName}:" -msgstr "You are about to remove the following user from the organisation <0>{organisationName}:" +msgstr "You are about to remove the following user from the organization <0>{organisationName}:" #: apps/remix/app/components/dialogs/admin-team-member-delete-dialog.tsx msgid "You are about to remove the following user from the team <0>{teamName}:" @@ -14306,7 +14306,7 @@ msgstr "You authenticated with the signing provider" #: packages/lib/utils/document-audit-logs.ts msgid "You authorised the remote signature" -msgstr "You authorised the remote signature" +msgstr "You authorized the remote signature" #: apps/remix/app/components/dialogs/ai-field-detection-dialog.tsx msgid "You can add fields manually in the editor." @@ -14334,7 +14334,7 @@ msgstr "You can copy and share these links to recipients so they can action the #: apps/remix/app/components/general/teams/team-inherit-member-alert.tsx msgid "You can enable access to allow all organisation members to access this team by default." -msgstr "You can enable access to allow all organisation members to access this team by default." +msgstr "You can enable access to allow all organization members to access this team by default." #: apps/remix/app/routes/_authenticated+/o.$orgUrl.settings.email.tsx #: apps/remix/app/routes/_authenticated+/t.$teamUrl+/settings.email.tsx @@ -14371,7 +14371,7 @@ msgstr "You can view the document and its status by clicking the button below." #: packages/lib/utils/document-audit-logs.ts msgid "You cancelled the document" -msgstr "You cancelled the document" +msgstr "You canceled the document" #: apps/remix/app/components/general/envelope-editor/envelope-editor-recipient-form.tsx #: packages/ui/primitives/document-flow/add-signers.tsx @@ -14393,7 +14393,7 @@ msgstr "You cannot modify a group which has a higher role than you." #: apps/remix/app/components/dialogs/organisation-member-update-dialog.tsx msgid "You cannot modify a organisation member who has a higher role than you." -msgstr "You cannot modify a organisation member who has a higher role than you." +msgstr "You cannot modify a organization member who has a higher role than you." #: apps/remix/app/components/dialogs/team-member-update-dialog.tsx msgid "You cannot modify a team member who has a higher role than you." @@ -14409,7 +14409,7 @@ msgstr "You cannot remove members from this team while the inherit member featur #: apps/remix/app/components/dialogs/team-member-delete-dialog.tsx msgid "You cannot remove the organisation owner from the team." -msgstr "You cannot remove the organisation owner from the team." +msgstr "You cannot remove the organization owner from the team." #: packages/ui/primitives/document-dropzone.tsx #: packages/ui/primitives/document-upload-button.tsx @@ -14457,7 +14457,7 @@ msgstr "You currently have an inactive <0>{currentProductName} subscription. #: apps/remix/app/routes/_authenticated+/o.$orgUrl._index.tsx msgid "You currently have no access to any teams within this organisation. Please contact your organisation to request access." -msgstr "You currently have no access to any teams within this organisation. Please contact your organisation to request access." +msgstr "You currently have no access to any teams within this organization. Please contact your organization to request access." #. placeholder {0}: data.envelopeItemTitle #: packages/lib/utils/document-audit-logs.ts @@ -14474,11 +14474,11 @@ msgstr "You do not have permission to create a token for this team." #: apps/remix/app/components/general/unified-settings-sidebar.tsx msgid "You don't have permission to manage this organisation. Switch to another one above, or continue in your team settings below." -msgstr "You don't have permission to manage this organisation. Switch to another one above, or continue in your team settings below." +msgstr "You don't have permission to manage this organization. Switch to another one above, or continue in your team settings below." #: apps/remix/app/components/tables/user-billing-organisations-table.tsx msgid "You don't manage billing for any organisations." -msgstr "You don't manage billing for any organisations." +msgstr "You don't manage billing for any organizations." #: packages/email/template-components/template-document-cancel.tsx msgid "You don't need to sign it anymore." @@ -14490,7 +14490,7 @@ msgstr "You failed to validate a 2FA token for the document" #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "You have accepted an invitation from <0>{organisationName} to join their organisation." -msgstr "You have accepted an invitation from <0>{organisationName} to join their organisation." +msgstr "You have accepted an invitation from <0>{organisationName} to join their organization." #. placeholder {0}: data.teamName #: apps/remix/app/routes/_unauthenticated+/team.verify.email.$token.tsx @@ -14499,7 +14499,7 @@ msgstr "You have already verified your email address for <0>{0}." #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "You have been invited by <0>{organisationName} to join their organisation." -msgstr "You have been invited by <0>{organisationName} to join their organisation." +msgstr "You have been invited by <0>{organisationName} to join their organization." #. placeholder {0}: organisation.name #: packages/lib/server-only/organisation/create-organisation-member-invites.ts @@ -14512,7 +14512,7 @@ msgstr "You have been invited to join <0>{organisationName} on Documenso." #: packages/email/templates/organisation-invite.tsx msgid "You have been invited to join the following organisation" -msgstr "You have been invited to join the following organisation" +msgstr "You have been invited to join the following organization" #: packages/lib/jobs/definitions/emails/send-recipient-removed-email.handler.ts msgid "You have been removed from a document" @@ -14524,7 +14524,7 @@ msgstr "You have been requested to sign the following documents. Review each doc #: apps/remix/app/routes/_unauthenticated+/organisation.invite.$token.tsx msgid "You have declined the invitation from <0>{organisationName} to join their organisation." -msgstr "You have declined the invitation from <0>{organisationName} to join their organisation." +msgstr "You have declined the invitation from <0>{organisationName} to join their organization." #. placeholder {0}: `"${envelope.title}"` #: packages/lib/jobs/definitions/emails/send-signing-email.handler.ts @@ -14594,7 +14594,7 @@ msgstr "You have signed “{documentName}”" #: apps/remix/app/components/dialogs/organisation-leave-dialog.tsx msgid "You have successfully left this organisation." -msgstr "You have successfully left this organisation." +msgstr "You have successfully left this organization." #: apps/remix/app/components/forms/signup.tsx #: apps/remix/app/components/general/claim-account.tsx @@ -14603,11 +14603,11 @@ msgstr "You have successfully registered. Please verify your account by clicking #: apps/remix/app/components/dialogs/organisation-email-domain-delete-dialog.tsx msgid "You have successfully removed this email domain from the organisation." -msgstr "You have successfully removed this email domain from the organisation." +msgstr "You have successfully removed this email domain from the organization." #: apps/remix/app/components/dialogs/organisation-email-delete-dialog.tsx msgid "You have successfully removed this email from the organisation." -msgstr "You have successfully removed this email from the organisation." +msgstr "You have successfully removed this email from the organization." #: apps/remix/app/components/dialogs/envelope-item-delete-dialog.tsx msgid "You have successfully removed this envelope item." @@ -14615,7 +14615,7 @@ msgstr "You have successfully removed this envelope item." #: apps/remix/app/components/dialogs/organisation-group-delete-dialog.tsx msgid "You have successfully removed this group from the organisation." -msgstr "You have successfully removed this group from the organisation." +msgstr "You have successfully removed this group from the organization." #: apps/remix/app/components/dialogs/team-group-delete-dialog.tsx msgid "You have successfully removed this group from the team." @@ -14623,7 +14623,7 @@ msgstr "You have successfully removed this group from the team." #: apps/remix/app/components/dialogs/organisation-member-delete-dialog.tsx msgid "You have successfully removed this user from the organisation." -msgstr "You have successfully removed this user from the organisation." +msgstr "You have successfully removed this user from the organization." #: apps/remix/app/components/dialogs/team-member-delete-dialog.tsx msgid "You have successfully removed this user from the team." @@ -14879,7 +14879,7 @@ msgstr "You viewed the document" #: apps/remix/app/components/dialogs/admin-organisation-create-dialog.tsx msgid "You will need to configure any claims or subscription after creating this organisation" -msgstr "You will need to configure any claims or subscription after creating this organisation" +msgstr "You will need to configure any claims or subscription after creating this organization" #: apps/remix/app/components/forms/2fa/enable-authenticator-app-dialog.tsx msgid "You will now be required to enter a code from your authenticator app when signing in." @@ -15114,64 +15114,64 @@ msgstr "Your new password cannot be the same as your old password." #: apps/remix/app/components/dialogs/organisation-create-dialog.tsx msgid "Your organisation has been created." -msgstr "Your organisation has been created." +msgstr "Your organization has been created." #: packages/email/templates/organisation-delete.tsx #: packages/email/templates/organisation-delete.tsx msgid "Your organisation has been deleted" -msgstr "Your organisation has been deleted" +msgstr "Your organization has been deleted" #: apps/remix/app/components/dialogs/organisation-delete-dialog.tsx msgid "Your organisation has been successfully deleted." -msgstr "Your organisation has been successfully deleted." +msgstr "Your organization has been successfully deleted." #: apps/remix/app/components/forms/organisation-update-form.tsx msgid "Your organisation has been successfully updated." -msgstr "Your organisation has been successfully updated." +msgstr "Your organization has been successfully updated." #: apps/remix/app/components/general/organisations/organisation-quota-banner.tsx msgid "Your organisation has exceeded a fair use limit" -msgstr "Your organisation has exceeded a fair use limit" +msgstr "Your organization has exceeded a fair use limit" #: apps/remix/app/components/general/organisations/organisation-quota-banner.tsx msgid "Your organisation has exceeded a fair use limit. Please contact <0>support to review your plan's limits." -msgstr "Your organisation has exceeded a fair use limit. Please contact <0>support to review your plan's limits." +msgstr "Your organization has exceeded a fair use limit. Please contact <0>support to review your plan's limits." #: apps/remix/app/utils/toast-error-messages.ts msgid "Your organisation has reached its plan's fair use limit. Please contact your organisation administrator or support to continue." -msgstr "Your organisation has reached its plan's fair use limit. Please contact your organisation administrator or support to continue." +msgstr "Your organization has reached its plan's fair use limit. Please contact your organization administrator or support to continue." #: apps/remix/app/components/general/organisations/organisation-quota-banner.tsx msgid "Your organisation is approaching a fair use limit" -msgstr "Your organisation is approaching a fair use limit" +msgstr "Your organization is approaching a fair use limit" #: apps/remix/app/components/general/organisations/organisation-quota-banner.tsx msgid "Your organisation is approaching a fair use limit. If you expect to need higher limits, please contact <0>support to review your plan's limits." -msgstr "Your organisation is approaching a fair use limit. If you expect to need higher limits, please contact <0>support to review your plan's limits." +msgstr "Your organization is approaching a fair use limit. If you expect to need higher limits, please contact <0>support to review your plan's limits." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is generating API requests faster than normal, so some requests are being temporarily throttled." -msgstr "Your organisation is generating API requests faster than normal, so some requests are being temporarily throttled." +msgstr "Your organization is generating API requests faster than normal, so some requests are being temporarily throttled." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is generating documents faster than normal, so some requests are being temporarily throttled." -msgstr "Your organisation is generating documents faster than normal, so some requests are being temporarily throttled." +msgstr "Your organization is generating documents faster than normal, so some requests are being temporarily throttled." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is generating emails faster than normal, so some requests are being temporarily throttled." -msgstr "Your organisation is generating emails faster than normal, so some requests are being temporarily throttled." +msgstr "Your organization is generating emails faster than normal, so some requests are being temporarily throttled." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is nearing its fair use limits for creating documents on your current plan. Once the limit is reached, new document activity will be temporarily paused." -msgstr "Your organisation is nearing its fair use limits for creating documents on your current plan. Once the limit is reached, new document activity will be temporarily paused." +msgstr "Your organization is nearing its fair use limits for creating documents on your current plan. Once the limit is reached, new document activity will be temporarily paused." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is nearing its fair use limits for making API requests on your current plan. Once the limit is reached, new API activity will be temporarily paused." -msgstr "Your organisation is nearing its fair use limits for making API requests on your current plan. Once the limit is reached, new API activity will be temporarily paused." +msgstr "Your organization is nearing its fair use limits for making API requests on your current plan. Once the limit is reached, new API activity will be temporarily paused." #: packages/email/templates/organisation-limit-alert.tsx msgid "Your organisation is nearing its fair use limits for sending email on your current plan. Once the limit is reached, new email activity will be temporarily paused." -msgstr "Your organisation is nearing its fair use limits for sending email on your current plan. Once the limit is reached, new email activity will be temporarily paused." +msgstr "Your organization is nearing its fair use limits for sending email on your current plan. Once the limit is reached, new email activity will be temporarily paused." #: apps/remix/app/components/forms/password.tsx #: apps/remix/app/components/forms/reset-password.tsx @@ -15226,7 +15226,7 @@ msgstr "Your remote signature was applied" #: apps/remix/app/components/general/document-signing/csc-recipient-signing-in-progress-page.tsx msgid "Your signing authorisation expired before the signature could be applied. Please reauthorise to retry." -msgstr "Your signing authorisation expired before the signature could be applied. Please reauthorise to retry." +msgstr "Your signing authorization expired before the signature could be applied. Please reauthorize to retry." #: apps/remix/app/components/general/document-signing/csc-recipient-blocked-page.tsx msgid "Your signing certificate is invalid, expired, or missing a required key. Contact your administrator or signing provider for assistance." From 2cac63a000e22422bdea449f68b8025e709aa73a Mon Sep 17 00:00:00 2001 From: Martin Glaser <65476570+martindglaser@users.noreply.github.com> Date: Fri, 4 Sep 2026 02:42:39 -0300 Subject: [PATCH 34/64] fix: block SSRF via IPv4-mapped IPv6 webhook URLs (#2901) (#3166) --- .../webhooks/is-private-url.test.ts | 19 +++++++++++----- .../server-only/webhooks/is-private-url.ts | 22 +++++++++++++++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/lib/server-only/webhooks/is-private-url.test.ts b/packages/lib/server-only/webhooks/is-private-url.test.ts index 841ed7938..d0c122818 100644 --- a/packages/lib/server-only/webhooks/is-private-url.test.ts +++ b/packages/lib/server-only/webhooks/is-private-url.test.ts @@ -81,13 +81,20 @@ describe('isPrivateUrl', () => { expect(isPrivateUrl('http://[fd12::1]')).toBe(true); }); - it('should not catch IPv4-mapped IPv6 in URL form (URL parser normalizes to hex)', () => { - // new URL() normalizes "::ffff:127.0.0.1" to "::ffff:7f00:1" which none - // of the checks handle. This is fine because dns.lookup never returns - // IPv4-mapped addresses — it returns plain IPv4 (family: 4) instead. - expect(isPrivateUrl('http://[::ffff:127.0.0.1]')).toBe(false); - expect(isPrivateUrl('http://[::ffff:10.0.0.1]')).toBe(false); + it('should detect private IPv4-mapped IPv6 addresses (URL parser normalizes to hex)', () => { + // new URL() normalizes "::ffff:127.0.0.1" to the hex form "::ffff:7f00:1", + // so the embedded IPv4 must be decoded and re-checked. Otherwise a literal + // host such as http://[::ffff:127.0.0.1] bypasses every dotted-decimal + // check above (SSRF, see #2901). + expect(isPrivateUrl('http://[::ffff:127.0.0.1]')).toBe(true); + expect(isPrivateUrl('http://[::ffff:10.0.0.1]')).toBe(true); + expect(isPrivateUrl('http://[::ffff:192.168.0.1]')).toBe(true); + expect(isPrivateUrl('http://[::ffff:169.254.169.254]')).toBe(true); + }); + + it('should still allow public IPv4-mapped IPv6 addresses', () => { expect(isPrivateUrl('http://[::ffff:8.8.8.8]')).toBe(false); + expect(isPrivateUrl('http://[::ffff:1.1.1.1]')).toBe(false); }); }); diff --git a/packages/lib/server-only/webhooks/is-private-url.ts b/packages/lib/server-only/webhooks/is-private-url.ts index 38f531ee0..c75966792 100644 --- a/packages/lib/server-only/webhooks/is-private-url.ts +++ b/packages/lib/server-only/webhooks/is-private-url.ts @@ -69,11 +69,25 @@ export const isPrivateUrl = (url: string): boolean => { } } - // IPv4-mapped IPv6 (e.g. ::ffff:127.0.0.1) - const v4Mapped = normalizedHost.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i); + // IPv4-mapped IPv6, dotted form (e.g. ::ffff:127.0.0.1) + const v4MappedDotted = normalizedHost.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i); - if (v4Mapped) { - return isPrivateUrl(`http://${v4Mapped[1]}`); + if (v4MappedDotted) { + return isPrivateUrl(`http://${v4MappedDotted[1]}`); + } + + // IPv4-mapped IPv6, hex form (e.g. ::ffff:7f00:1). `new URL()` normalizes the + // dotted form above to this, so it must be decoded to the embedded IPv4 as + // well - otherwise a literal host such as `http://[::ffff:127.0.0.1]` slips + // through every dotted-decimal check above (SSRF, see #2901). + const v4MappedHex = normalizedHost.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i); + + if (v4MappedHex) { + const high = parseInt(v4MappedHex[1], 16); + const low = parseInt(v4MappedHex[2], 16); + const ipv4 = [high >> 8, high & 0xff, low >> 8, low & 0xff].join('.'); + + return isPrivateUrl(`http://${ipv4}`); } return false; From 6a8bb4be04b6f0417dbfd0a385d0099fab2686e2 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Tue, 8 Sep 2026 21:03:02 +1000 Subject: [PATCH 35/64] fix: improve invalid bulk template upload error handling (#3326) --- .../dialogs/template-bulk-send-dialog.tsx | 123 ++++++++++- .../internal/bulk-send-template.handler.ts | 52 +---- .../template/validate-bulk-send-csv.test.ts | 208 ++++++++++++++++++ .../template/validate-bulk-send-csv.ts | 117 ++++++++++ .../trpc/server/template-router/router.ts | 12 +- 5 files changed, 461 insertions(+), 51 deletions(-) create mode 100644 packages/lib/server-only/template/validate-bulk-send-csv.test.ts create mode 100644 packages/lib/server-only/template/validate-bulk-send-csv.ts diff --git a/apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx b/apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx index 7e381c82f..7e610f469 100644 --- a/apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx +++ b/apps/remix/app/components/dialogs/template-bulk-send-dialog.tsx @@ -1,4 +1,7 @@ +import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error'; +import type { TBulkSendCsvError } from '@documenso/lib/server-only/template/validate-bulk-send-csv'; import { trpc } from '@documenso/trpc/react'; +import { Alert, AlertDescription } from '@documenso/ui/primitives/alert'; import { Button } from '@documenso/ui/primitives/button'; import { Checkbox } from '@documenso/ui/primitives/checkbox'; import { @@ -17,7 +20,9 @@ import { msg } from '@lingui/core/macro'; import { useLingui } from '@lingui/react'; import { Trans } from '@lingui/react/macro'; import { File as FileIcon, Upload, X } from 'lucide-react'; +import { useState } from 'react'; import { useForm } from 'react-hook-form'; +import { match } from 'ts-pattern'; import { z } from 'zod'; import { useCurrentTeam } from '~/providers/team'; @@ -29,6 +34,8 @@ const ZBulkSendFormSchema = z.object({ type TBulkSendFormSchema = z.infer; +type TBulkSendValidationError = TBulkSendCsvError | { type: 'UPLOAD_ERROR'; code: string }; + export type TemplateBulkSendDialogProps = { templateId: number; recipients: Array<{ email: string; name?: string | null }>; @@ -42,6 +49,9 @@ export const TemplateBulkSendDialog = ({ templateId, recipients, trigger, onSucc const team = useCurrentTeam(); + const [open, setOpen] = useState(false); + const [validationError, setValidationError] = useState(null); + const form = useForm({ resolver: zodResolver(ZBulkSendFormSchema), defaultValues: { @@ -51,6 +61,20 @@ export const TemplateBulkSendDialog = ({ templateId, recipients, trigger, onSucc const { mutateAsync: uploadBulkSend } = trpc.template.uploadBulkSend.useMutation(); + const onOpenChange = (value: boolean) => { + if (form.formState.isSubmitting) { + return; + } + + setOpen(value); + + if (!value) { + setValidationError(null); + + form.reset(); + } + }; + const onDownloadTemplate = () => { const headers = recipients.flatMap((_, index) => [`recipient_${index + 1}_email`, `recipient_${index + 1}_name`]); @@ -71,36 +95,44 @@ export const TemplateBulkSendDialog = ({ templateId, recipients, trigger, onSucc }; const onSubmit = async (values: TBulkSendFormSchema) => { + setValidationError(null); + try { const csv = await values.file.text(); - await uploadBulkSend({ + const result = await uploadBulkSend({ templateId, teamId: team?.id, csv: csv, sendImmediately: values.sendImmediately, }); + if (!result.success) { + setValidationError(result.error); + + return; + } + toast({ title: _(msg`Success`), description: _(msg`Your bulk send has been initiated. You will receive an email notification upon completion.`), }); + setOpen(false); form.reset(); + onSuccess?.(); } catch (err) { console.error(err); - toast({ - title: _(msg`Error`), - description: _(msg`Failed to upload CSV. Please check the file format and try again.`), - variant: 'destructive', - }); + const error = AppError.parseError(err); + + setValidationError({ type: 'UPLOAD_ERROR', code: error.code }); } }; return ( - + {trigger ?? ( diff --git a/packages/lib/jobs/definitions/internal/bulk-send-template.handler.ts b/packages/lib/jobs/definitions/internal/bulk-send-template.handler.ts index cb57b42a2..3db217eda 100644 --- a/packages/lib/jobs/definitions/internal/bulk-send-template.handler.ts +++ b/packages/lib/jobs/definitions/internal/bulk-send-template.handler.ts @@ -2,12 +2,10 @@ import { BulkSendCompleteEmail } from '@documenso/email/templates/bulk-send-comp import { sendDocument } from '@documenso/lib/server-only/document/send-document'; import { createDocumentFromTemplate } from '@documenso/lib/server-only/template/create-document-from-template'; import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id'; -import { zEmail } from '@documenso/lib/utils/zod'; +import { validateBulkSendCsv } from '@documenso/lib/server-only/template/validate-bulk-send-csv'; import { prisma } from '@documenso/prisma'; import { msg } from '@lingui/macro'; -import { parse } from 'csv-parse/sync'; import { createElement } from 'react'; -import { z } from 'zod'; import { getI18nInstance } from '../../../client-only/providers/i18n-server'; import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app'; @@ -17,14 +15,6 @@ import { renderEmailWithI18N } from '../../../utils/render-email-with-i18n'; import type { JobRunIO } from '../../client/_internal/job'; import type { TBulkSendTemplateJobDefinition } from './bulk-send-template'; -const ZRecipientRowSchema = z.object({ - name: z.string().optional(), - email: z.union([ - zEmail('Value must be a valid email or empty string'), - z.string().max(0, { message: 'Value must be a valid email or empty string' }), - ]), -}); - export const run = async ({ payload, io }: { payload: TBulkSendTemplateJobDefinition; io: JobRunIO }) => { const { userId, teamId, templateId, csvContent, sendImmediately, requestMetadata } = payload; @@ -41,25 +31,21 @@ export const run = async ({ payload, io }: { payload: TBulkSendTemplateJobDefini throw new Error('Template not found'); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const rows = parse(csvContent, { columns: true, skip_empty_lines: true }); - - if (rows.length > 100) { - throw new Error('Maximum 100 rows allowed per upload'); - } - const { recipients } = template; - // Validate CSV structure - const csvHeaders = Object.keys(rows[0]); - const requiredHeaders = recipients.map((_, index) => `recipient_${index + 1}_email`); + // The CSV is validated upfront when the bulk send is uploaded, this acts as + // a final safeguard prior to processing. + const csvValidationResult = validateBulkSendCsv({ + csvContent, + recipientCount: recipients.length, + }); - for (const header of requiredHeaders) { - if (!csvHeaders.includes(header)) { - throw new Error(`Missing required column: ${header}`); - } + if (!csvValidationResult.success) { + throw new Error(`Bulk send CSV failed validation: ${JSON.stringify(csvValidationResult.error)}`); } + const rows = csvValidationResult.data; + const user = await prisma.user.findFirstOrThrow({ where: { id: userId, @@ -79,22 +65,6 @@ export const run = async ({ payload, io }: { payload: TBulkSendTemplateJobDefini // Process each row for (const [rowIndex, row] of rows.entries()) { try { - for (const [recipientIndex] of recipients.entries()) { - const nameKey = `recipient_${recipientIndex + 1}_name`; - const emailKey = `recipient_${recipientIndex + 1}_email`; - - const parsed = ZRecipientRowSchema.safeParse({ - name: row[nameKey], - email: row[emailKey], - }); - - if (!parsed.success) { - throw new Error( - `Invalid recipient data provided for ${emailKey}, ${nameKey}: ${parsed.error.issues?.[0]?.message}`, - ); - } - } - const envelope = await io.runTask(`create-document-${rowIndex}`, async () => { return await createDocumentFromTemplate({ id: { diff --git a/packages/lib/server-only/template/validate-bulk-send-csv.test.ts b/packages/lib/server-only/template/validate-bulk-send-csv.test.ts new file mode 100644 index 000000000..799b0c541 --- /dev/null +++ b/packages/lib/server-only/template/validate-bulk-send-csv.test.ts @@ -0,0 +1,208 @@ +import { describe, expect, it } from 'vitest'; + +import type { TBulkSendCsvError, TValidateBulkSendCsvResult } from './validate-bulk-send-csv'; +import { validateBulkSendCsv } from './validate-bulk-send-csv'; + +const buildCsv = (headers: string[], rows: string[][]) => + [headers.join(','), ...rows.map((row) => row.join(','))].join('\n'); + +const expectFailure = (result: TValidateBulkSendCsvResult): TBulkSendCsvError => { + if (result.success) { + throw new Error('Expected validation to fail, but it passed'); + } + + return result.error; +}; + +describe('validateBulkSendCsv', () => { + describe('valid CSVs', () => { + it('returns the parsed rows for a valid CSV', () => { + const csvContent = buildCsv( + ['recipient_1_email', 'recipient_1_name'], + [ + ['alice@example.com', 'Alice'], + ['bob@example.com', 'Bob'], + ], + ); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 1 }); + + expect(result).toEqual({ + success: true, + data: [ + { recipient_1_email: 'alice@example.com', recipient_1_name: 'Alice' }, + { recipient_1_email: 'bob@example.com', recipient_1_name: 'Bob' }, + ], + }); + }); + + it('allows an empty string email so template defaults can be used', () => { + const csvContent = buildCsv(['recipient_1_email', 'recipient_1_name'], [['', 'Alice']]); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 1 }); + + expect(result.success).toBe(true); + }); + + it('allows the optional name column to be omitted entirely', () => { + const csvContent = buildCsv(['recipient_1_email'], [['alice@example.com']]); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 1 }); + + expect(result.success).toBe(true); + }); + + it('allows unknown extra columns', () => { + const csvContent = buildCsv(['recipient_1_email', 'unrelated_column'], [['alice@example.com', 'anything']]); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 1 }); + + expect(result.success).toBe(true); + }); + + it('validates columns for every configured recipient', () => { + const csvContent = buildCsv( + ['recipient_1_email', 'recipient_2_email'], + [['alice@example.com', 'bob@example.com']], + ); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 2 }); + + expect(result.success).toBe(true); + }); + + it('allows exactly the maximum number of rows', () => { + const csvContent = buildCsv( + ['recipient_1_email'], + Array.from({ length: 100 }, (_, index) => [`user${index}@example.com`]), + ); + + const result = validateBulkSendCsv({ csvContent, recipientCount: 1 }); + + expect(result.success).toBe(true); + }); + }); + + describe('PARSE_ERROR', () => { + it('rejects a CSV that cannot be parsed', () => { + const csvContent = 'recipient_1_email\n"unclosed quote'; + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toEqual({ type: 'PARSE_ERROR' }); + }); + + it('rejects a CSV with inconsistent column counts', () => { + const csvContent = buildCsv( + ['recipient_1_email', 'recipient_1_name'], + [['alice@example.com', 'Alice', 'unexpected-extra-value']], + ); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toEqual({ type: 'PARSE_ERROR' }); + }); + }); + + describe('EMPTY', () => { + it('rejects an empty file', () => { + const error = expectFailure(validateBulkSendCsv({ csvContent: '', recipientCount: 1 })); + + expect(error).toEqual({ type: 'EMPTY' }); + }); + + it('rejects a CSV containing only a header row', () => { + const csvContent = buildCsv(['recipient_1_email', 'recipient_1_name'], []); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toEqual({ type: 'EMPTY' }); + }); + }); + + describe('ROW_LIMIT_EXCEEDED', () => { + it('rejects a CSV exceeding the default limit of 100 rows', () => { + const csvContent = buildCsv( + ['recipient_1_email'], + Array.from({ length: 101 }, (_, index) => [`user${index}@example.com`]), + ); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toEqual({ type: 'ROW_LIMIT_EXCEEDED', rowCount: 101, maxRows: 100 }); + }); + + it('respects a custom maxRows option', () => { + const csvContent = buildCsv(['recipient_1_email'], [['alice@example.com'], ['bob@example.com']]); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1, maxRows: 1 })); + + expect(error).toEqual({ type: 'ROW_LIMIT_EXCEEDED', rowCount: 2, maxRows: 1 }); + }); + }); + + describe('MISSING_COLUMNS', () => { + it('rejects a CSV missing a required email column', () => { + const csvContent = buildCsv(['recipient_1_name'], [['Alice']]); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toEqual({ type: 'MISSING_COLUMNS', missingColumns: ['recipient_1_email'] }); + }); + + it('reports every missing column', () => { + const csvContent = buildCsv(['recipient_1_email'], [['alice@example.com']]); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 3 })); + + expect(error).toEqual({ + type: 'MISSING_COLUMNS', + missingColumns: ['recipient_2_email', 'recipient_3_email'], + }); + }); + }); + + describe('INVALID_RECIPIENTS', () => { + it('rejects a CSV containing an invalid email', () => { + const csvContent = buildCsv(['recipient_1_email'], [['not-an-email']]); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toMatchObject({ + type: 'INVALID_RECIPIENTS', + rowErrors: [{ row: 1, column: 'recipient_1_email' }], + }); + }); + + it('references the offending row and column', () => { + const csvContent = buildCsv(['recipient_1_email'], [['alice@example.com'], ['not-an-email']]); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 1 })); + + expect(error).toMatchObject({ + type: 'INVALID_RECIPIENTS', + rowErrors: [{ row: 2, column: 'recipient_1_email' }], + }); + }); + + it('aggregates errors across multiple rows and recipients', () => { + const csvContent = buildCsv( + ['recipient_1_email', 'recipient_2_email'], + [ + ['not-an-email', 'bob@example.com'], + ['alice@example.com', 'also-not-an-email'], + ], + ); + + const error = expectFailure(validateBulkSendCsv({ csvContent, recipientCount: 2 })); + + expect(error).toMatchObject({ + type: 'INVALID_RECIPIENTS', + rowErrors: [ + { row: 1, column: 'recipient_1_email' }, + { row: 2, column: 'recipient_2_email' }, + ], + }); + }); + }); +}); diff --git a/packages/lib/server-only/template/validate-bulk-send-csv.ts b/packages/lib/server-only/template/validate-bulk-send-csv.ts new file mode 100644 index 000000000..3afc1d7c5 --- /dev/null +++ b/packages/lib/server-only/template/validate-bulk-send-csv.ts @@ -0,0 +1,117 @@ +import { parse } from 'csv-parse/sync'; +import { z } from 'zod'; + +import { zEmail } from '../../utils/zod'; + +const ZRecipientRowSchema = z.object({ + name: z.string().optional(), + email: z.union([ + zEmail('Value must be a valid email or empty string'), + z.string().max(0, { message: 'Value must be a valid email or empty string' }), + ]), +}); + +export type TBulkSendCsvRow = Record; + +export type TBulkSendCsvRowError = { + /** + * The 1-indexed row number the error occurred on, excluding the header row. + */ + row: number; + + /** + * The column the error occurred in, such as `recipient_1_email`. + */ + column: string; + + message: string; +}; + +export type TBulkSendCsvError = + | { type: 'PARSE_ERROR' } + | { type: 'EMPTY' } + | { type: 'ROW_LIMIT_EXCEEDED'; rowCount: number; maxRows: number } + | { type: 'MISSING_COLUMNS'; missingColumns: string[] } + | { type: 'INVALID_RECIPIENTS'; rowErrors: TBulkSendCsvRowError[] }; + +export type TValidateBulkSendCsvResult = + | { success: true; data: TBulkSendCsvRow[] } + | { success: false; error: TBulkSendCsvError }; + +export type ValidateBulkSendCsvOptions = { + csvContent: string; + + /** + * The number of recipients configured on the template, used to derive the + * required `recipient_N_email` columns. + */ + recipientCount: number; + + maxRows?: number; +}; + +/** + * Validate the CSV provided for a template bulk send. + * + * Returns a discriminated union so callers can surface structured error + * details, such as which rows contain invalid recipients. + */ +export const validateBulkSendCsv = ({ + csvContent, + recipientCount, + maxRows = 100, +}: ValidateBulkSendCsvOptions): TValidateBulkSendCsvResult => { + let rows: TBulkSendCsvRow[]; + + try { + rows = parse(csvContent, { columns: true, skip_empty_lines: true }); + } catch { + return { success: false, error: { type: 'PARSE_ERROR' } }; + } + + if (rows.length === 0) { + return { success: false, error: { type: 'EMPTY' } }; + } + + if (rows.length > maxRows) { + return { success: false, error: { type: 'ROW_LIMIT_EXCEEDED', rowCount: rows.length, maxRows } }; + } + + const csvHeaders = Object.keys(rows[0]); + + const requiredHeaders = Array.from({ length: recipientCount }, (_, index) => `recipient_${index + 1}_email`); + + const missingColumns = requiredHeaders.filter((header) => !csvHeaders.includes(header)); + + if (missingColumns.length > 0) { + return { success: false, error: { type: 'MISSING_COLUMNS', missingColumns } }; + } + + const rowErrors: TBulkSendCsvRowError[] = []; + + for (const [rowIndex, row] of rows.entries()) { + for (let recipientIndex = 0; recipientIndex < recipientCount; recipientIndex += 1) { + const nameKey = `recipient_${recipientIndex + 1}_name`; + const emailKey = `recipient_${recipientIndex + 1}_email`; + + const parsed = ZRecipientRowSchema.safeParse({ + name: row[nameKey], + email: row[emailKey], + }); + + if (!parsed.success) { + rowErrors.push({ + row: rowIndex + 1, + column: emailKey, + message: parsed.error.issues?.[0]?.message ?? 'Invalid value', + }); + } + } + } + + if (rowErrors.length > 0) { + return { success: false, error: { type: 'INVALID_RECIPIENTS', rowErrors } }; + } + + return { success: true, data: rows }; +}; diff --git a/packages/trpc/server/template-router/router.ts b/packages/trpc/server/template-router/router.ts index e11e1f25d..00c4816f8 100644 --- a/packages/trpc/server/template-router/router.ts +++ b/packages/trpc/server/template-router/router.ts @@ -22,6 +22,7 @@ import { findTemplates } from '@documenso/lib/server-only/template/find-template import { getOrganisationTemplateById } from '@documenso/lib/server-only/template/get-organisation-template-by-id'; import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id'; import { toggleTemplateDirectLink } from '@documenso/lib/server-only/template/toggle-template-direct-link'; +import { validateBulkSendCsv } from '@documenso/lib/server-only/template/validate-bulk-send-csv'; import { fireAndForget } from '@documenso/lib/universal/fire-and-forget'; import { putNormalizedPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server'; import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions'; @@ -879,6 +880,15 @@ export const templateRouter = router({ }); } + const csvValidationResult = validateBulkSendCsv({ + csvContent: csv, + recipientCount: template.recipients.length, + }); + + if (!csvValidationResult.success) { + return { success: false as const, error: csvValidationResult.error }; + } + await jobs.triggerJob({ name: 'internal.bulk-send-template', payload: { @@ -891,6 +901,6 @@ export const templateRouter = router({ }, }); - return { success: true }; + return { success: true as const }; }), }); From 5e8a4341410cd114f7089c42648f52ea5de77f3f Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Wed, 9 Sep 2026 10:51:26 +1000 Subject: [PATCH 36/64] fix: use react router middleware (#3351) --- apps/remix/app/entry.server.tsx | 7 +++-- apps/remix/app/middleware/admin.ts | 13 +++++++++ apps/remix/app/middleware/nonce.ts | 8 +++++ apps/remix/app/root.tsx | 7 +++-- .../routes/_authenticated+/admin+/_layout.tsx | 8 +++-- apps/remix/app/utils/nonce.ts | 8 ++++- apps/remix/react-router.config.ts | 3 ++ apps/remix/server/context.ts | 5 ++-- apps/remix/server/load-context.ts | 29 ++++--------------- 9 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 apps/remix/app/middleware/admin.ts create mode 100644 apps/remix/app/middleware/nonce.ts diff --git a/apps/remix/app/entry.server.tsx b/apps/remix/app/entry.server.tsx index 7f28001f4..895ccba93 100644 --- a/apps/remix/app/entry.server.tsx +++ b/apps/remix/app/entry.server.tsx @@ -7,10 +7,11 @@ import { createReadableStreamFromReadable } from '@react-router/node'; import { isbot } from 'isbot'; import type { RenderToPipeableStreamOptions } from 'react-dom/server'; import { renderToPipeableStream } from 'react-dom/server'; -import type { AppLoadContext, EntryContext } from 'react-router'; +import type { EntryContext, RouterContextProvider } from 'react-router'; import { ServerRouter } from 'react-router'; import { langCookie } from './storage/lang-cookie.server'; +import { nonceContext } from './utils/nonce'; export const streamTimeout = 5_000; @@ -19,7 +20,7 @@ export default async function handleRequest( responseStatusCode: number, responseHeaders: Headers, routerContext: EntryContext, - loadContext: AppLoadContext, + loadContext: RouterContextProvider, ) { let language = await langCookie.parse(request.headers.get('cookie') ?? ''); @@ -33,7 +34,7 @@ export default async function handleRequest( // scripts it injects (route manifest, hydration data, module preloads). // The same nonce is also exposed to the React tree via the root loader so // our own inline scripts/styles can carry it. - const nonce = loadContext.nonce || undefined; + const nonce = loadContext.get(nonceContext) || undefined; return new Promise((resolve, reject) => { let shellRendered = false; diff --git a/apps/remix/app/middleware/admin.ts b/apps/remix/app/middleware/admin.ts new file mode 100644 index 000000000..0eef2c90d --- /dev/null +++ b/apps/remix/app/middleware/admin.ts @@ -0,0 +1,13 @@ +import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session'; +import { isAdmin } from '@documenso/lib/utils/is-admin'; +import { type MiddlewareFunction, redirect } from 'react-router'; + +export const adminMiddleware: MiddlewareFunction = async ({ request }, next) => { + const { user } = await getOptionalSession(request); + + if (!user || !isAdmin(user)) { + throw redirect('/'); + } + + return next(); +}; diff --git a/apps/remix/app/middleware/nonce.ts b/apps/remix/app/middleware/nonce.ts new file mode 100644 index 000000000..916d5232d --- /dev/null +++ b/apps/remix/app/middleware/nonce.ts @@ -0,0 +1,8 @@ +import type { MiddlewareFunction } from 'react-router'; + +import { getRequestNonce } from '../../server/load-context'; +import { nonceContext } from '../utils/nonce'; + +export const nonceMiddleware: MiddlewareFunction = ({ context }) => { + context.set(nonceContext, getRequestNonce()); +}; diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx index baffaa6ec..e317068df 100644 --- a/apps/remix/app/root.tsx +++ b/apps/remix/app/root.tsx @@ -23,13 +23,16 @@ import { useMatches, } from 'react-router'; import { PreventFlashOnWrongTheme, ThemeProvider, useTheme } from 'remix-themes'; +import { nonceMiddleware } from '~/middleware/nonce'; import type { Route } from './+types/root'; import stylesheet from './app.css?url'; import { GenericErrorLayout } from './components/general/generic-error-layout'; import { langCookie } from './storage/lang-cookie.server'; import { themeSessionResolver } from './storage/theme-session.server'; import { appMetaTags } from './utils/meta'; -import { nonce } from './utils/nonce'; +import { nonce, nonceContext } from './utils/nonce'; + +export const middleware = [nonceMiddleware]; export const links: Route.LinksFunction = () => [{ rel: 'stylesheet', href: stylesheet }]; @@ -74,7 +77,7 @@ export async function loader({ context, request }: Route.LoaderArgs) { // Surface the per-request CSP nonce produced by `securityHeadersMiddleware` so all // SSR-rendered