diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 60b385403..3471f4f88 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -10,7 +10,13 @@
"ghcr.io/devcontainers/features/node:1": {}
},
"onCreateCommand": "./.devcontainer/on-create.sh",
- "forwardPorts": [3000, 54320, 9000, 2500, 1100],
+ "forwardPorts": [
+ 3000,
+ 54320,
+ 9000,
+ 2500,
+ 1100
+ ],
"customizations": {
"vscode": {
"extensions": [
@@ -25,8 +31,8 @@
"GitHub.copilot",
"GitHub.vscode-pull-request-github",
"Prisma.prisma",
- "VisualStudioExptTeam.vscodeintellicode",
+ "VisualStudioExptTeam.vscodeintellicode"
]
}
}
-}
+}
\ No newline at end of file
diff --git a/.github/actions/cache-build/action.yml b/.github/actions/cache-build/action.yml
new file mode 100644
index 000000000..e1eb4da22
--- /dev/null
+++ b/.github/actions/cache-build/action.yml
@@ -0,0 +1,24 @@
+name: Cache production build binaries
+description: 'Cache or restore if necessary'
+inputs:
+ node_version:
+ required: false
+ default: v18.x
+runs:
+ using: 'composite'
+ steps:
+ - name: Cache production build
+ uses: actions/cache@v3
+ id: production-build-cache
+ with:
+ path: |
+ ${{ github.workspace }}/apps/web/.next
+ ${{ github.workspace }}/apps/marketing/.next
+ **/.turbo/**
+ **/dist/**
+
+ key: prod-build-${{ github.run_id }}
+ restore-keys: prod-build-
+
+ - run: npm run build
+ shell: bash
diff --git a/.github/actions/node-install/action.yml b/.github/actions/node-install/action.yml
new file mode 100644
index 000000000..77483a9a4
--- /dev/null
+++ b/.github/actions/node-install/action.yml
@@ -0,0 +1,39 @@
+name: 'Setup node and cache node_modules'
+inputs:
+ node_version:
+ required: false
+ default: v18.x
+
+runs:
+ using: 'composite'
+ steps:
+ - name: Set up Node ${{ inputs.node_version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ inputs.node_version }}
+
+ - name: Cache npm
+ uses: actions/cache@v3
+ with:
+ path: ~/.npm
+ key: npm-${{ hashFiles('package-lock.json') }}
+ restore-keys: npm-
+
+ - name: Cache node_modules
+ uses: actions/cache@v3
+ id: cache-node-modules
+ with:
+ path: |
+ node_modules
+ packages/*/node_modules
+ apps/*/node_modules
+ key: modules-${{ hashFiles('package-lock.json') }}
+
+ - name: Install dependencies
+ if: steps.cache-node-modules.outputs.cache-hit != 'true'
+ shell: bash
+ run: |
+ npm ci --no-audit
+ npm run prisma:generate
+ env:
+ HUSKY: '0'
diff --git a/.github/actions/playwright-install/action.yml b/.github/actions/playwright-install/action.yml
new file mode 100644
index 000000000..27d0e66b4
--- /dev/null
+++ b/.github/actions/playwright-install/action.yml
@@ -0,0 +1,19 @@
+name: Install playwright binaries
+description: 'Install playwright, cache and restore if necessary'
+runs:
+ using: 'composite'
+ steps:
+ - name: Cache playwright
+ id: cache-playwright
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.cache/ms-playwright
+ ${{ github.workspace }}/node_modules/playwright
+ key: playwright-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: playwright-
+
+ - name: Install playwright
+ if: steps.cache-playwright.outputs.cache-hit != 'true'
+ run: npx playwright install --with-deps
+ shell: bash
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index deda53ff0..bebca8e85 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,6 +1,7 @@
name: 'Continuous Integration'
on:
+ workflow_call:
push:
branches: ['main']
pull_request:
@@ -10,9 +11,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
-env:
- HUSKY: 0
-
jobs:
build_app:
name: Build App
@@ -23,20 +21,12 @@ jobs:
with:
fetch-depth: 2
- - name: Install Node.js
- uses: actions/setup-node@v4
- with:
- node-version: 18
- cache: npm
-
- - name: Install dependencies
- run: npm ci
+ - uses: ./.github/actions/node-install
- name: Copy env
run: cp .env.example .env
- - name: Build
- run: npm run build
+ - uses: ./.github/actions/cache-build
build_docker:
name: Build Docker Image
@@ -47,5 +37,31 @@ jobs:
with:
fetch-depth: 2
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Cache Docker layers
+ uses: actions/cache@v3
+ with:
+ path: /tmp/.buildx-cache
+ key: ${{ runner.os }}-buildx-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-buildx-
+
- name: Build Docker Image
- run: ./docker/build.sh
+ uses: docker/build-push-action@v5
+ with:
+ push: false
+ context: .
+ file: ./docker/Dockerfile
+ tags: documenso-${{ github.sha }}
+ cache-from: type=local,src=/tmp/.buildx-cache
+ cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
+
+ - # Temp fix
+ # https://github.com/docker/build-push-action/issues/252
+ # https://github.com/moby/buildkit/issues/1896
+ name: Move cache
+ run: |
+ rm -rf /tmp/.buildx-cache
+ mv /tmp/.buildx-cache-new /tmp/.buildx-cache
diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml
new file mode 100644
index 000000000..2cb13f661
--- /dev/null
+++ b/.github/workflows/clean-cache.yml
@@ -0,0 +1,29 @@
+name: cleanup caches by a branch
+on:
+ pull_request:
+ types:
+ - closed
+
+jobs:
+ cleanup:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cleanup
+ run: |
+ gh extension install actions/gh-actions-cache
+
+ echo "Fetching list of cache key"
+ cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 )
+
+ ## Setting this to not fail the workflow while deleting cache keys.
+ set +e
+ echo "Deleting caches..."
+ for cacheKey in $cacheKeysForPR
+ do
+ gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
+ done
+ echo "Done"
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ REPO: ${{ github.repository }}
+ BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 465041c0a..314dc7b7b 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -25,19 +25,12 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: 18
- cache: npm
-
- - name: Install Dependencies
- run: npm ci
-
- name: Copy env
run: cp .env.example .env
- - name: Build Documenso
- run: npm run build
+ - uses: ./.github/actions/node-install
+
+ - uses: ./.github/actions/cache-build
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 7b05458d9..12a7d9521 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -6,29 +6,21 @@ on:
branches: ['main']
jobs:
e2e_tests:
- name: "E2E Tests"
+ name: 'E2E Tests'
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: 18
- cache: npm
- - name: Install dependencies
- run: npm ci
- name: Copy env
run: cp .env.example .env
+ - uses: ./.github/actions/node-install
+
- name: Start Services
run: npm run dx:up
- - name: Install Playwright Browsers
- run: npx playwright install --with-deps
-
- - name: Generate Prisma Client
- run: npm run prisma:generate -w @documenso/prisma
+ - uses: ./.github/actions/playwright-install
- name: Create the database
run: npm run prisma:migrate-dev
@@ -36,6 +28,8 @@ jobs:
- name: Seed the database
run: npm run prisma:seed
+ - uses: ./.github/actions/cache-build
+
- name: Run Playwright tests
run: npm run ci
@@ -43,7 +37,7 @@ jobs:
if: always()
with:
name: test-results
- path: "packages/app-tests/**/test-results/*"
+ path: 'packages/app-tests/**/test-results/*'
retention-days: 30
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..f69ddb57b
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,133 @@
+name: Publish Docker
+
+on:
+ push:
+ branches: ['release']
+
+jobs:
+ build_and_publish_platform_containers:
+ name: Build and publish platform containers
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - warp-ubuntu-latest-x64-4x
+ - warp-ubuntu-latest-arm64-4x
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-tags: true
+
+ - name: Login to DockerHub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GH_TOKEN }}
+
+ - name: Build the docker image
+ env:
+ BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
+ run: |
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ GIT_SHA="$(git rev-parse HEAD)"
+
+ docker build \
+ -f ./docker/Dockerfile \
+ --progress=plain \
+ -t "documenso/documenso-$BUILD_PLATFORM:latest" \
+ -t "documenso/documenso-$BUILD_PLATFORM:$GIT_SHA" \
+ -t "documenso/documenso-$BUILD_PLATFORM:$APP_VERSION" \
+ -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:latest" \
+ -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$GIT_SHA" \
+ -t "ghcr.io/documenso/documenso-$BUILD_PLATFORM:$APP_VERSION" \
+ .
+
+ - name: Push the docker image to DockerHub
+ run: docker push --all-tags "documenso/documenso-$BUILD_PLATFORM"
+ env:
+ BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
+
+ - name: Push the docker image to GitHub Container Registry
+ run: docker push --all-tags "ghcr.io/documenso/documenso-$BUILD_PLATFORM"
+ env:
+ BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-4x' && 'arm64' || 'amd64' }}
+
+ create_and_publish_manifest:
+ name: Create and publish manifest
+ runs-on: ubuntu-latest
+ needs: build_and_publish_platform_containers
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-tags: true
+
+ - name: Login to DockerHub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GH_TOKEN }}
+
+ - name: Create and push DockerHub manifest
+ run: |
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ GIT_SHA="$(git rev-parse HEAD)"
+
+ docker manifest create \
+ documenso/documenso:latest \
+ --amend documenso/documenso-amd64:latest \
+ --amend documenso/documenso-arm64:latest \
+
+ docker manifest create \
+ documenso/documenso:$GIT_SHA \
+ --amend documenso/documenso-amd64:$GIT_SHA \
+ --amend documenso/documenso-arm64:$GIT_SHA \
+
+ docker manifest create \
+ documenso/documenso:$APP_VERSION \
+ --amend documenso/documenso-amd64:$APP_VERSION \
+ --amend documenso/documenso-arm64:$APP_VERSION \
+
+ docker manifest push documenso/documenso:latest
+ docker manifest push documenso/documenso:$GIT_SHA
+ docker manifest push documenso/documenso:$APP_VERSION
+
+ - name: Create and push Github Container Registry manifest
+ run: |
+ APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
+ GIT_SHA="$(git rev-parse HEAD)"
+
+ docker manifest create \
+ ghcr.io/documenso/documenso:latest \
+ --amend ghcr.io/documenso/documenso-amd64:latest \
+ --amend ghcr.io/documenso/documenso-arm64:latest \
+
+ docker manifest create \
+ ghcr.io/documenso/documenso:$GIT_SHA \
+ --amend ghcr.io/documenso/documenso-amd64:$GIT_SHA \
+ --amend ghcr.io/documenso/documenso-arm64:$GIT_SHA \
+
+ docker manifest create \
+ ghcr.io/documenso/documenso:$APP_VERSION \
+ --amend ghcr.io/documenso/documenso-amd64:$APP_VERSION \
+ --amend ghcr.io/documenso/documenso-arm64:$APP_VERSION \
+
+ docker manifest push ghcr.io/documenso/documenso:latest
+ docker manifest push ghcr.io/documenso/documenso:$GIT_SHA
+ docker manifest push ghcr.io/documenso/documenso:$APP_VERSION
diff --git a/README.md b/README.md
index 6d2fab334..93c6d9f95 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
->We are nominated for a Product Hunt Gold Kitty ๐บโจ and appreciate any support: https://documen.so/kitty
-
Create a{' '} @@ -203,7 +203,7 @@ export const SinglePlayerClient = () => { target="_blank" className="hover:text-foreground/80 font-semibold transition-colors" > - community plan + early adopter plan {' '} for exclusive features, including the ability to collaborate with multiple signers.
@@ -256,6 +256,7 @@ export const SinglePlayerClient = () => { fields={fields} onSubmit={onSignSubmit} requireName={Boolean(fields.find((field) => field.type === 'NAME'))} + requireCustomText={Boolean(fields.find((field) => field.type === 'TEXT'))} requireSignature={Boolean(fields.find((field) => field.type === 'SIGNATURE'))} /> diff --git a/apps/marketing/src/app/layout.tsx b/apps/marketing/src/app/layout.tsx index 57da42c3f..99a1a6483 100644 --- a/apps/marketing/src/app/layout.tsx +++ b/apps/marketing/src/app/layout.tsx @@ -2,6 +2,8 @@ import { Suspense } from 'react'; import { Caveat, Inter } from 'next/font/google'; +import { PublicEnvScript } from 'next-runtime-env'; + import { FeatureFlagProvider } from '@documenso/lib/client-only/providers/feature-flag'; import { NEXT_PUBLIC_MARKETING_URL } from '@documenso/lib/constants/app'; import { getAllAnonymousFlags } from '@documenso/lib/universal/get-feature-flag'; @@ -62,6 +64,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo +Early Adopters
@@ -114,33 +118,31 @@ export const PricingTable = ({ className, ...props }: PricingTableProps) => {
- {' '}
-
- The Early Adopter Deal:
+
+
+ Limited Time Offer: Read More
Join the movement Simple signing solution Unlimited Teams Unlimited Users Unlimited Documents per month Includes all upcoming features Email, Discord and Slack assistance
-
- {' '}
-
- Includes all upcoming features
-
-
- Fixed, straightforward pricing
Create a{' '} diff --git a/apps/marketing/src/components/(marketing)/widget.tsx b/apps/marketing/src/components/(marketing)/widget.tsx index fe7502d27..8b6c3cd8e 100644 --- a/apps/marketing/src/components/(marketing)/widget.tsx +++ b/apps/marketing/src/components/(marketing)/widget.tsx @@ -199,7 +199,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => { className="bg-foreground/5 col-span-12 flex flex-col rounded-2xl p-6 lg:col-span-5" onSubmit={handleSubmit(onFormSubmit)} > -
with Timur Ercan & Lucas Smith from Documenso
@@ -208,7 +208,7 @@ export const Widget = ({ className, children, ...props }: WidgetProps) => {+ The site banner is a message that is shown at the top of the site. It can be used to display + important information to your users. +
+ + + +Unable to load document history
+ +No recent activity
++ + {formatDocumentAuditLogAction(auditLog, userId).prefix} + {' '} + {formatDocumentAuditLogAction(auditLog, userId).description} +
+ + ++ {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName} +
+ } + /> + + {document.status !== DocumentStatus.DRAFT && + recipient.signingStatus === SigningStatus.SIGNED && ( ++ {match(document.status) + .with( + DocumentStatus.COMPLETED, + () => 'This document has been signed by all recipients', + ) + .with( + DocumentStatus.DRAFT, + () => 'This document is currently a draft and has not been sent', + ) + .with(DocumentStatus.PENDING, () => { + const pendingRecipients = recipients.filter( + (recipient) => recipient.signingStatus === 'NOT_SIGNED', + ); + + return `Waiting on ${pendingRecipients.length} recipient${ + pendingRecipients.length > 1 ? 's' : '' + }`; + }) + .exhaustive()} +
+ ++ {row.original.name} +
+ )} + + {row.original.email && ( ++ {row.original.email} +
+ )} +N/A
+ ), + }, + { + header: 'Action', + accessorKey: 'type', + cell: ({ row }) => ( + + {uppercaseFistLetter(formatDocumentAuditLogAction(row.original).description)} + + ), + }, + { + header: 'IP Address', + accessorKey: 'ipAddress', + }, + { + header: 'Browser', + cell: ({ row }) => { + if (!row.original.userAgent) { + return 'N/A'; + } + + parser.setUA(row.original.userAgent); + + const result = parser.getResult(); + + return result.browser.name ?? 'N/A'; + }, + }, + ]} + data={results.data} + perPage={results.perPage} + currentPage={results.currentPage} + totalPages={results.totalPages} + onPaginationChange={onPaginationChange} + error={{ + enable: isLoadingError, + }} + skeleton={{ + enable: isLoading && isInitialLoading, + rows: 3, + component: ( + <> +{info.value}
+- You can upload up to {quota.documents} documents per month on your current plan. -
- - - Upgrade your account to upload more documents. - -- View all recent security activity related to your account. -
+
+ On this page, you can create new API tokens and manage the existing ones.
+ You can view our swagger docs{' '}
+
+ here
+
+
+ Your tokens will be shown here once you create them. +
+
+ Created on
+ Expires on
+ Token doesn't have an expiration date +
+ )} ++ You have no webhooks yet. Your webhooks will be shown here once you create them. +
++ Listening to{' '} + {webhook.eventTriggers + .map((trigger) => toFriendlyWebhookEventName(trigger)) + .join(', ')} +
+ +
+ Created on{' '}
+
Text
+ )} + + {field.inserted &&{field.customText}
} + + +- Current plan: {teamSubscription ? 'Team' : 'Community Team'} + Current plan: {teamSubscription ? 'Team' : 'Early Adopter Team'}
diff --git a/apps/web/src/app/(teams)/t/[teamUrl]/settings/tokens/page.tsx b/apps/web/src/app/(teams)/t/[teamUrl]/settings/tokens/page.tsx new file mode 100644 index 000000000..eedae29d1 --- /dev/null +++ b/apps/web/src/app/(teams)/t/[teamUrl]/settings/tokens/page.tsx @@ -0,0 +1,94 @@ +import { DateTime } from 'luxon'; + +import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app'; +import { getRequiredServerComponentSession } from '@documenso/lib/next-auth/get-server-component-session'; +import { getTeamTokens } from '@documenso/lib/server-only/public-api/get-all-team-tokens'; +import { getTeamByUrl } from '@documenso/lib/server-only/team/get-team'; +import { Button } from '@documenso/ui/primitives/button'; + +import DeleteTokenDialog from '~/components/(dashboard)/settings/token/delete-token-dialog'; +import { LocaleDate } from '~/components/formatter/locale-date'; +import { ApiTokenForm } from '~/components/forms/token'; + +type ApiTokensPageProps = { + params: { + teamUrl: string; + }; +}; + +export default async function ApiTokensPage({ params }: ApiTokensPageProps) { + const { teamUrl } = params; + + const { user } = await getRequiredServerComponentSession(); + + const team = await getTeamByUrl({ userId: user.id, teamUrl }); + + const tokens = await getTeamTokens({ userId: user.id, teamId: team.id }); + + return ( +
+ On this page, you can create new API tokens and manage the existing ones.
+ You can view our swagger docs{' '}
+
+ here
+
+
+ Your tokens will be shown here once you create them. +
+
+ Created on
+ Expires on
+ Token doesn't have an expiration date +
+ )} ++ You have no webhooks yet. Your webhooks will be shown here once you create them. +
++ Listening to{' '} + {webhook.eventTriggers + .map((trigger) => toFriendlyWebhookEventName(trigger)) + .join(', ')} +
+ +
+ Created on{' '}
+
- A password reset email has been sent, if you have an account you should see it in your inbox - shortly. -
++ A password reset email has been sent, if you have an account you should see it in your + inbox shortly. +
- + +- No worries, it happens! Enter your email and we'll email you a special link to reset your - password. -
++ No worries, it happens! Enter your email and we'll email you a special link to reset your + password. +
-- Remembered your password?{' '} - - Sign In - -
++ Remembered your password?{' '} + + Sign In + +
+Please choose your new password
+Please choose your new password
-- Don't have an account?{' '} - - Sign up - -
++ Don't have an account?{' '} + + Sign up + +
+- The token you have used to reset your password is either expired or it never existed. If you - have still forgotten your password, please request a new reset link. -
++ The token you have used to reset your password is either expired or it never existed. If + you have still forgotten your password, please request a new reset link. +
- + +- Welcome back, we are lucky to have you. -
- -- Don't have an account?{' '} - - Sign up - +
+ Welcome back, we are lucky to have you.
- )} -- - Forgot your password? - -
++ Don't have an account?{' '} + + Sign up + +
+ )} +- Create your account and start using state-of-the-art document signing. Open and beautiful - signing is within your grasp. -
- -- Already have an account?{' '} - - Sign in instead - -
-- This token is invalid or has expired. Please contact your team for a new invitation. -
++ This token is invalid or has expired. Please contact your team for a new invitation. +
- + +- This link is invalid or has expired. Please contact your team to resend a verification. -
++ This link is invalid or has expired. Please contact your team to resend a verification. +
- + +- This link is invalid or has expired. Please contact your team to resend a transfer - request. -
++ This link is invalid or has expired. Please contact your team to resend a transfer + request. +
- + +- To gain access to your account, please confirm your email address by clicking on the - confirmation link from your inbox. -
++ To gain access to your account, please confirm your email address by clicking on the + confirmation link from your inbox. +
-- If you don't find the confirmation link in your inbox, you can request a new one below. -
++ If you don't find the confirmation link in your inbox, you can request a new one below. +
-- It seems that there is no token provided. Please check your email and try again. -
++ It seems that there is no token provided. Please check your email and try again. +
+- We were unable to verify your email. If your email is not verified already, please try - again. -
++ We were unable to verify your email. If your email is not verified already, please try + again. +
- + ++ It seems that the provided token has expired. We've just sent you another token, + please check your email and try again. +
+ + +- It seems that the provided token has expired. We've just sent you another token, please - check your email and try again. + Your email has been successfully confirmed! You can now use all features of Documenso.
- Your email has been successfully confirmed! You can now use all features of Documenso. -
- - -- It seems that there is no token provided, if you are trying to verify your email please - follow the link in your email. -
++ It seems that there is no token provided, if you are trying to verify your email please + follow the link in your email. +
- + +{recipient.email}
-- {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName} -
-{recipient.email}
++ {RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName} +
+