mirror of
https://github.com/documenso/documenso.git
synced 2026-07-22 07:53:40 +10:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a9721740d | |||
| 42a7d3efd7 | |||
| a46f668e71 |
@@ -65,4 +65,3 @@ When you exceed a resource limit:
|
||||
- [Authentication](/docs/developers/getting-started/authentication) - API authentication guide
|
||||
- [API Versioning](/docs/developers/api/versioning) - API version management
|
||||
- [First API Call](/docs/developers/getting-started/first-api-call) - Getting started with the API
|
||||
- [Organisation Limits](/docs/self-hosting/configuration/organisation-limits) - Admins: set per-organisation resource quotas and rate limits (the HTTP rate limit above is separate and not admin-settable)
|
||||
|
||||
@@ -76,8 +76,6 @@ The Enterprise Edition is required when you:
|
||||
4. Restart your Documenso instance
|
||||
5. Verify the license is active in the **Admin Panel** under the **Stats** section
|
||||
|
||||
See [Apply Your License Key](/docs/self-hosting/configuration/license) for the full walkthrough, including how to enable individual features once licensed.
|
||||
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
@@ -199,7 +197,7 @@ See [Support](/docs/policies/support) for complete support options.
|
||||
1. Sign the Enterprise license agreement
|
||||
2. Receive license key and access credentials
|
||||
3. Deploy using [self-hosting guides](/docs/self-hosting) or access Documenso Cloud
|
||||
4. Apply the key — see [Apply Your License Key](/docs/self-hosting/configuration/license) — and configure Enterprise features with support assistance
|
||||
4. Configure Enterprise features with support assistance
|
||||
|
||||
</Step>
|
||||
<Step>
|
||||
@@ -240,7 +238,6 @@ See [Support](/docs/policies/support) for complete support options.
|
||||
|
||||
## Related
|
||||
|
||||
- [Apply Your License Key](/docs/self-hosting/configuration/license) - Step-by-step license activation
|
||||
- [Community Edition](/docs/policies/community-edition) - AGPL-3.0 open-source license
|
||||
- [Licenses](/docs/policies/licenses) - Complete licensing overview and FAQ
|
||||
- [Support](/docs/policies/support) - Support channels and response times
|
||||
|
||||
@@ -443,11 +443,11 @@ Telemetry collects only: app version, installation ID, and node ID. No personal
|
||||
|
||||
## Enterprise Features
|
||||
|
||||
These variables require an active [Enterprise Edition](/docs/policies/enterprise-edition) license. Obtain a license key from [license.documenso.com](https://license.documenso.com) and set it below to unlock enterprise features such as SSO, embed editor, and 21 CFR Part 11 compliance. See [Apply Your License Key](/docs/self-hosting/configuration/license) for step-by-step setup.
|
||||
These variables require an active [Enterprise Edition](/docs/policies/enterprise-edition) license. Obtain a license key from [license.documenso.com](https://license.documenso.com) and set it below to unlock enterprise features such as SSO, embed editor, and 21 CFR Part 11 compliance.
|
||||
|
||||
| Variable | Description |
|
||||
| ------------------------------------ | ------------------------------------------------ |
|
||||
| `NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY` | License key for enterprise features — see [Apply Your License Key](/docs/self-hosting/configuration/license) for how to apply it |
|
||||
| `NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY` | License key for enterprise features |
|
||||
| `NEXT_PRIVATE_STRIPE_API_KEY` | Stripe API key for billing |
|
||||
| `NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET` | Stripe webhook secret |
|
||||
| `NEXT_PRIVATE_SES_ACCESS_KEY_ID` | AWS SES access key for email domain verification |
|
||||
@@ -510,5 +510,4 @@ NEXT_PRIVATE_SIGNING_PASSPHRASE="your-certificate-password"
|
||||
- [Email Configuration](/docs/self-hosting/configuration/email) - Configure email delivery
|
||||
- [Storage Configuration](/docs/self-hosting/configuration/storage) - Set up S3 storage
|
||||
- [Signing Certificate](/docs/self-hosting/configuration/signing-certificate) - Configure document signing
|
||||
- [Organisation Limits](/docs/self-hosting/configuration/organisation-limits) - Set per-organisation document, email, and API limits from the admin panel
|
||||
- [Troubleshooting](/docs/self-hosting/maintenance/troubleshooting) - Common configuration issues
|
||||
|
||||
@@ -29,11 +29,6 @@ description: Configure your self-hosted Documenso instance with environment vari
|
||||
description="Digital signature certificate setup."
|
||||
href="/docs/self-hosting/configuration/signing-certificate"
|
||||
/>
|
||||
<Card
|
||||
title="Organisation Limits"
|
||||
description="Set per-organisation document, email, and API limits via the admin panel."
|
||||
href="/docs/self-hosting/configuration/organisation-limits"
|
||||
/>
|
||||
</Cards>
|
||||
|
||||
## Required Configuration
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
title: Apply Your License Key
|
||||
description: Activate your Enterprise license key to unlock enterprise features on your self-hosted instance.
|
||||
---
|
||||
|
||||
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
|
||||
import { Callout } from 'fumadocs-ui/components/callout';
|
||||
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
|
||||
|
||||
A license key activates the Enterprise features available to your self-hosted instance, such as CSC signing, SSO, embed white-labelling, and 21 CFR Part 11 compliance.
|
||||
|
||||
<Callout type="info">
|
||||
The license key applies to your **whole instance**, not an individual user account. There's one
|
||||
key per deployment.
|
||||
</Callout>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An active Enterprise license key — contact [sales](https://documen.so/enterprise) to set up an
|
||||
Enterprise subscription, then copy your key from [license.documenso.com](https://license.documenso.com).
|
||||
See [Enterprise Edition](/docs/policies/enterprise-edition) for details.
|
||||
- A running self-hosted Documenso instance that you're able to restart
|
||||
|
||||
## Step 1: Set the environment variable
|
||||
|
||||
Set `NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY` to your license key.
|
||||
|
||||
<Tabs items={['Docker Compose', 'docker run', '.env']}>
|
||||
<Tab value="Docker Compose">
|
||||
|
||||
Add the variable to your `.env` file (or directly under `environment:` in `compose.yml`):
|
||||
|
||||
```bash
|
||||
NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY=your-license-key-here
|
||||
```
|
||||
|
||||
Then apply it:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab value="docker run">
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name documenso \
|
||||
-e NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY=your-license-key-here \
|
||||
documenso/documenso:latest
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab value=".env">
|
||||
|
||||
If you're running Documenso directly (not in a container), add the variable to your `.env` file:
|
||||
|
||||
```bash
|
||||
NEXT_PRIVATE_DOCUMENSO_LICENSE_KEY=your-license-key-here
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Step 2: Restart the instance
|
||||
|
||||
The license key is only read once, at process startup. Setting the variable in a running container or shell has no effect until the process restarts.
|
||||
|
||||
```bash
|
||||
# Docker Compose
|
||||
docker compose restart documenso
|
||||
|
||||
# Docker
|
||||
docker restart documenso
|
||||
```
|
||||
|
||||
On startup, Documenso validates the key against the Documenso license server and caches the result locally for future startups, so a brief license-server outage won't lock you out.
|
||||
|
||||
## What the license enables
|
||||
|
||||
A valid license doesn't turn every enterprise feature on everywhere — activation depends on the feature:
|
||||
|
||||
- **CSC signing** activates instance-wide automatically once the license is active and CSC transport is configured. See [CSC / QES Signing](/docs/self-hosting/configuration/signing-certificate/csc-qes) for the full setup.
|
||||
- **SSO, embed white-labelling, 21 CFR Part 11, and similar** are provisioned per organisation. Follow each feature's own guide to configure it once the license is active.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
<Accordions type="multiple">
|
||||
<Accordion title="Enterprise features are still unavailable after applying the key">
|
||||
- Confirm the key is present in the environment the running process actually reads — `docker
|
||||
exec` into the container and check `env | grep LICENSE` if unsure.
|
||||
- Confirm the instance was fully restarted after the variable was set, not just reloaded.
|
||||
- Re-copy the key to rule out truncation or accidental whitespace.
|
||||
</Accordion>
|
||||
<Accordion title="A specific feature still isn't working">
|
||||
Instance-wide features (like CSC signing) also need their own configuration — an active license
|
||||
alone isn't enough. Check that feature's guide to confirm the required settings are in place.
|
||||
Per-organisation features additionally need to be provisioned for the organisation that's using
|
||||
them.
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
## See Also
|
||||
|
||||
- [Environment Variables](/docs/self-hosting/configuration/environment) - Complete configuration reference
|
||||
- [Enterprise Edition](/docs/policies/enterprise-edition) - What's included and how to purchase a license
|
||||
- [CSC / QES Signing](/docs/self-hosting/configuration/signing-certificate/csc-qes) - Enable CSC-based signing
|
||||
@@ -2,14 +2,12 @@
|
||||
"title": "Configuration",
|
||||
"pages": [
|
||||
"environment",
|
||||
"license",
|
||||
"database",
|
||||
"email",
|
||||
"storage",
|
||||
"background-jobs",
|
||||
"signing-certificate",
|
||||
"telemetry",
|
||||
"organisation-limits",
|
||||
"advanced"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
---
|
||||
title: Organisation Limits
|
||||
description: View and set per-organisation document, email, and API limits on a self-hosted Documenso instance using the admin panel's subscription claims.
|
||||
---
|
||||
|
||||
import { Callout } from 'fumadocs-ui/components/callout';
|
||||
|
||||
Per-organisation limits — document, email, and API usage, plus feature toggles and team/member caps — are controlled by **subscription claims**. You configure them in the admin panel, not through environment variables.
|
||||
|
||||
There are three distinct kinds of limit:
|
||||
|
||||
| Limit | Caps | Admin-settable |
|
||||
| ---------------------- | ------------------------------------------------- | ----------------------- |
|
||||
| Resource quota | Documents, emails, and API requests **per month** | Yes — per claim and org |
|
||||
| Resource rate limit | The same resources over a short window (e.g. `1h`) | Yes — per claim and org |
|
||||
| Global HTTP rate limit | API requests per IP (100/min, hardcoded) | No — see [Limitations](#limitations) |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A running self-hosted Documenso instance.
|
||||
- An account with the **`ADMIN`** role — an account-level role, separate from organisation and team roles. New accounts are created with the `USER` role only. Grant the first admin by adding `ADMIN` to that user's `roles` directly in the database; after that, an existing admin can grant the role to others under **Admin Panel > Users > _(user)_ > Roles > Update user**.
|
||||
|
||||
Open the admin panel at `/admin`. The sidebar sections used below are **Claims**, **Organisations**, and **Organisation Stats**.
|
||||
|
||||
## Viewing usage
|
||||
|
||||
**One organisation:** open **Admin Panel > Organisations** and select it. The **Organisation usage** section shows the current period's document, email, and API usage against its quotas.
|
||||
|
||||
**All organisations:** open **Admin Panel > Organisation Stats** to sort and filter monthly usage. Filter by **claim** and by **period** (a UTC calendar month, shown as `YYYY-MM`), and switch between **Show usage**, **Show usage with quotas**, and **Show daily averages**.
|
||||
|
||||
<Callout type="warn">
|
||||
Usage counts **attempts**, not only successful actions. A request that exceeds a quota is still counted before it is rejected, so displayed usage can read higher than the number of actions that succeeded.
|
||||
</Callout>
|
||||
|
||||
## Subscription claims
|
||||
|
||||
A subscription claim is a named bundle of limits and feature flags (for example `Free`, `Individual`, `Teams`, `Platform`, or `Enterprise`). Claims are **templates**: when an organisation is created it receives a private copy of its claim and reads from that copy afterwards. Editing a claim template therefore affects organisations created later, not existing ones — to change an existing organisation, [edit it directly](#change-limits-for-one-organisation).
|
||||
|
||||
### Claim fields
|
||||
|
||||
Under **Admin Panel > Claims** (`/admin/claims`), each claim has:
|
||||
|
||||
| Field | Controls |
|
||||
| ----------------------- | --------------------------------------------------------------------------------- |
|
||||
| **Name** | The claim's display name. |
|
||||
| **Team Count** | Teams allowed. `0` = unlimited. |
|
||||
| **Member Count** | Members allowed. `0` = unlimited. |
|
||||
| **Envelope Item Count** | Uploaded files allowed per envelope. Minimum `1`. |
|
||||
| **Recipient Count** | Recipients allowed per document. `0` = unlimited. |
|
||||
| **Feature Flags** | Feature toggles (see [Feature flags](#feature-flags)). |
|
||||
| **Limits** | Monthly quota and rate-limit windows for Documents, Emails, and API. |
|
||||
| **Email transport** | Transport the claim uses. *Default (system mailer)* uses the instance default. |
|
||||
|
||||
### Quotas and rate limits
|
||||
|
||||
The **Limits** section has a column for **Documents**, **Emails**, and **API**, each with two controls:
|
||||
|
||||
- **Monthly quota** — how many of that resource are allowed per calendar month. An **empty** field is unlimited; **`0`** blocks the resource entirely.
|
||||
- **Rate limit windows** — optional short-window caps, each a duration and a maximum. A window is a number and a unit (`s`, `m`, `h`, `d`), such as `5m`, `1h`, or `24h`, and must be unique within the resource.
|
||||
|
||||
<Callout type="warn">
|
||||
Quotas and counts use opposite conventions for "unlimited": an **empty** quota is unlimited (and `0` blocks the resource), whereas `0` in the **Team**, **Member**, and **Recipient Count** fields means unlimited.
|
||||
</Callout>
|
||||
|
||||
### Feature flags
|
||||
|
||||
The **Feature Flags** section toggles capabilities such as Unlimited documents, Branding, Hide Documenso branding, Email domains, Embed authoring, Embed signing, White label for embed authoring/signing, 21 CFR, HIPAA, Authentication portal, Allow Legacy Envelopes, Signing reminders, QES signing, and Disable emails.
|
||||
|
||||
Some flags are Enterprise features. If your license does not include one, it is marked and cannot be enabled (you can still turn it off). See [Enterprise Edition](/docs/policies/enterprise-edition).
|
||||
|
||||
### Create or edit a claim template
|
||||
|
||||
1. Go to **Admin Panel > Claims**.
|
||||
2. Select **New claim**, or select an existing claim to edit it.
|
||||
3. Set the counts, feature flags, and the **Limits** section.
|
||||
4. Save. Changes apply to organisations created afterwards, not existing ones.
|
||||
|
||||
### Change limits for one organisation
|
||||
|
||||
To change limits for an existing organisation, edit it directly rather than its claim template.
|
||||
|
||||
1. Go to **Admin Panel > Organisations** and open the organisation.
|
||||
2. Adjust its quota, rate-limit, feature-flag, or email-transport fields.
|
||||
3. Save. Changes take effect immediately.
|
||||
|
||||
The organisation also shows the **Inherited subscription claim** it was created from.
|
||||
|
||||
## Usage reset
|
||||
|
||||
Monthly quota usage is keyed to the **UTC calendar month**. There is no scheduled reset job — when the month rolls over, the new period's counter starts at `0`.
|
||||
|
||||
## Limitations
|
||||
|
||||
The **global HTTP rate limit is not configurable.** Documenso enforces a hardcoded **100 requests per minute per IP address** on its API endpoint groups (`/api/v1`, `/api/v2`, and the tRPC API are limited separately), returning `429 Too Many Requests`. It is a per-IP safeguard applied at the HTTP layer — not per-organisation, not stored on any claim, and not adjustable from the admin panel. See [Rate Limits](/docs/developers/api/rate-limits).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Cause and fix |
|
||||
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| An organisation hit its limit unexpectedly | Usage counts rejected over-quota attempts. Compare usage against the quota under **Organisation Stats > Show usage with quotas**. |
|
||||
| A resource is blocked entirely, not just capped | The **Monthly quota** is `0`, which blocks the resource. Leave it empty for unlimited. |
|
||||
| Emails are not sending for an organisation | Check whether the **Disable emails** flag is enabled on the organisation's claim — it blocks all emails regardless of quota. |
|
||||
| A claim template edit had no effect | Template edits are not retroactive. Edit the organisation directly under **Admin Panel > Organisations**. |
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Environment Variables](/docs/self-hosting/configuration/environment) - All configuration options
|
||||
- [Rate Limits](/docs/developers/api/rate-limits) - The global HTTP API rate limit (separate from claims)
|
||||
- [Enterprise Edition](/docs/policies/enterprise-edition) - Features unlocked by license flags
|
||||
@@ -49,7 +49,7 @@ The callback URL is fixed — Documenso derives it from `NEXT_PUBLIC_WEBAPP_URL`
|
||||
|
||||
### Enterprise Edition license
|
||||
|
||||
CSC mode is gated by the `instanceCscSigning` license flag. Without a valid Enterprise license, the transport refuses to start (`CSC_UNLICENSED`). See [Apply Your License Key](/docs/self-hosting/configuration/license) to activate one.
|
||||
CSC mode is gated by the `instanceCscSigning` license flag. Without a valid Enterprise license, the transport refuses to start (`CSC_UNLICENSED`).
|
||||
|
||||
</Step>
|
||||
<Step>
|
||||
|
||||
@@ -141,7 +141,7 @@ See the [Quick Start guide](/docs/self-hosting/getting-started/quick-start) for
|
||||
|
||||
Self-hosted Documenso includes full core functionality under the AGPL-3.0 license. If you need enterprise features such as SSO, embed editor white label, or 21 CFR Part 11 compliance, you can activate them with a license key.
|
||||
|
||||
See [Enterprise Edition](/docs/policies/enterprise-edition) for details and [Licenses](/docs/policies/licenses) for a comparison. Already have a key? See [Apply Your License Key](/docs/self-hosting/configuration/license).
|
||||
See [Enterprise Edition](/docs/policies/enterprise-edition) for details and [Licenses](/docs/policies/licenses) for a comparison.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export const SignUpForm = ({
|
||||
password: '',
|
||||
signature: '',
|
||||
},
|
||||
mode: 'onChange',
|
||||
mode: 'onBlur',
|
||||
resolver: zodResolver(ZSignUpFormSchema),
|
||||
});
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
"@lingui/react": "^5.6.0",
|
||||
"@oslojs/crypto": "^1.0.1",
|
||||
"@oslojs/encoding": "^1.1.0",
|
||||
"@react-router/node": "^7.18.1",
|
||||
"@react-router/serve": "^7.18.1",
|
||||
"@react-router/node": "^7.12.0",
|
||||
"@react-router/serve": "^7.12.0",
|
||||
"@simplewebauthn/browser": "^13.2.2",
|
||||
"@simplewebauthn/server": "^13.2.2",
|
||||
"@tanstack/react-query": "5.90.10",
|
||||
@@ -81,8 +81,8 @@
|
||||
"@babel/preset-typescript": "^7.28.5",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.6.0",
|
||||
"@lingui/vite-plugin": "^5.6.0",
|
||||
"@react-router/dev": "^7.18.1",
|
||||
"@react-router/remix-routes-option-adapter": "^7.18.1",
|
||||
"@react-router/dev": "^7.12.0",
|
||||
"@react-router/remix-routes-option-adapter": "^7.12.0",
|
||||
"@rollup/plugin-babel": "^6.1.0",
|
||||
"@rollup/plugin-commonjs": "^28.0.9",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
@@ -106,5 +106,5 @@
|
||||
"vite-plugin-babel-macros": "^1.0.6",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
},
|
||||
"version": "2.15.0"
|
||||
"version": "2.14.0"
|
||||
}
|
||||
|
||||
Generated
+1267
-1931
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -5,7 +5,7 @@
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "2.15.0",
|
||||
"version": "2.14.0",
|
||||
"scripts": {
|
||||
"postinstall": "patch-package",
|
||||
"build": "turbo run build",
|
||||
|
||||
@@ -2,16 +2,27 @@ import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-c
|
||||
import { PDF_VIEWER_PAGE_SELECTOR } from '@documenso/lib/constants/pdf-viewer';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import type { Field, Recipient } from '@prisma/client';
|
||||
import { SigningStatus } from '@prisma/client';
|
||||
import { ClockIcon, EyeOffIcon, LockIcon } from 'lucide-react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { FieldType, SigningStatus } from '@prisma/client';
|
||||
import {
|
||||
CalendarDaysIcon,
|
||||
CheckSquareIcon,
|
||||
ChevronDownIcon,
|
||||
ContactIcon,
|
||||
DiscIcon,
|
||||
EyeOffIcon,
|
||||
HashIcon,
|
||||
LockIcon,
|
||||
MailIcon,
|
||||
TypeIcon,
|
||||
UserIcon,
|
||||
} from 'lucide-react';
|
||||
import { type ElementType, useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { isTemplateRecipientEmailPlaceholder } from '../../../lib/constants/template';
|
||||
import { extractInitials } from '../../../lib/utils/recipient-formatter';
|
||||
import { SignatureIcon } from '../../icons/signature';
|
||||
import { cn } from '../../lib/utils';
|
||||
import { Avatar, AvatarFallback } from '../../primitives/avatar';
|
||||
import { Badge } from '../../primitives/badge';
|
||||
import { FRIENDLY_FIELD_TYPE } from '../../primitives/document-flow/types';
|
||||
import { PopoverHover } from '../../primitives/popover';
|
||||
|
||||
@@ -27,16 +38,18 @@ interface EnvelopeRecipientFieldTooltipProps {
|
||||
showRecipientColors?: boolean;
|
||||
}
|
||||
|
||||
const getRecipientDisplayText = (recipient: { name: string; email: string }) => {
|
||||
if (recipient.name && !isTemplateRecipientEmailPlaceholder(recipient.email)) {
|
||||
return `${recipient.name} (${recipient.email})`;
|
||||
}
|
||||
|
||||
if (recipient.name && isTemplateRecipientEmailPlaceholder(recipient.email)) {
|
||||
return recipient.name;
|
||||
}
|
||||
|
||||
return recipient.email;
|
||||
const FIELD_TYPE_ICONS: Record<FieldType, ElementType> = {
|
||||
[FieldType.SIGNATURE]: SignatureIcon,
|
||||
[FieldType.FREE_SIGNATURE]: SignatureIcon,
|
||||
[FieldType.INITIALS]: ContactIcon,
|
||||
[FieldType.TEXT]: TypeIcon,
|
||||
[FieldType.DATE]: CalendarDaysIcon,
|
||||
[FieldType.EMAIL]: MailIcon,
|
||||
[FieldType.NAME]: UserIcon,
|
||||
[FieldType.NUMBER]: HashIcon,
|
||||
[FieldType.RADIO]: DiscIcon,
|
||||
[FieldType.CHECKBOX]: CheckSquareIcon,
|
||||
[FieldType.DROPDOWN]: ChevronDownIcon,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -50,6 +63,8 @@ export function EnvelopeRecipientFieldTooltip({
|
||||
}: EnvelopeRecipientFieldTooltipProps) {
|
||||
const { t } = useLingui();
|
||||
|
||||
const FieldIcon = FIELD_TYPE_ICONS[field.type];
|
||||
|
||||
const [hideField, setHideField] = useState<boolean>(!showRecipientTooltip);
|
||||
|
||||
const [coords, setCoords] = useState({
|
||||
@@ -138,54 +153,64 @@ export function EnvelopeRecipientFieldTooltip({
|
||||
</Avatar>
|
||||
}
|
||||
contentProps={{
|
||||
className: 'relative flex mb-4 w-fit flex-col p-4 text-sm',
|
||||
className: 'flex w-64 flex-col overflow-hidden p-0 text-sm',
|
||||
sideOffset: 20,
|
||||
onOpenAutoFocus: (event) => event.preventDefault(),
|
||||
}}
|
||||
>
|
||||
{showFieldStatus && (
|
||||
<Badge
|
||||
className="mx-auto mb-1 py-0.5"
|
||||
variant={
|
||||
field?.fieldMeta?.readOnly
|
||||
? 'neutral'
|
||||
: field.recipient.signingStatus === SigningStatus.SIGNED
|
||||
? 'default'
|
||||
: 'secondary'
|
||||
}
|
||||
>
|
||||
{field?.fieldMeta?.readOnly ? (
|
||||
<>
|
||||
<LockIcon className="mr-1 h-3 w-3" />
|
||||
<Trans>Read Only</Trans>
|
||||
</>
|
||||
) : field.recipient.signingStatus === SigningStatus.SIGNED ? (
|
||||
<>
|
||||
<SignatureIcon className="mr-1 h-3 w-3" />
|
||||
<Trans>Signed</Trans>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ClockIcon className="mr-1 h-3 w-3" />
|
||||
<Trans>Pending</Trans>
|
||||
</>
|
||||
)}
|
||||
</Badge>
|
||||
)}
|
||||
<div className="flex items-center gap-2 p-3">
|
||||
<FieldIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
|
||||
|
||||
<p className="text-center font-semibold">
|
||||
<span>
|
||||
<p className="min-w-0 flex-1 truncate font-medium">
|
||||
<Trans>{t(FRIENDLY_FIELD_TYPE[field.type])} field</Trans>
|
||||
</span>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
<p className="mt-1 text-center text-muted-foreground text-xs">{getRecipientDisplayText(field.recipient)}</p>
|
||||
{showFieldStatus && (
|
||||
<div className="flex shrink-0 items-center gap-1.5 text-xs">
|
||||
{field?.fieldMeta?.readOnly ? (
|
||||
<>
|
||||
<LockIcon className="h-3 w-3 text-muted-foreground" />
|
||||
<span className="text-muted-foreground">
|
||||
<Trans>Read Only</Trans>
|
||||
</span>
|
||||
</>
|
||||
) : field.recipient.signingStatus === SigningStatus.SIGNED ? (
|
||||
<>
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-green-500" />
|
||||
<span className="text-green-600 dark:text-green-400">
|
||||
<Trans>Signed</Trans>
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-amber-400" />
|
||||
<span className="text-amber-600 dark:text-amber-400">
|
||||
<Trans>Pending</Trans>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="absolute top-0 right-0 my-1 p-2 focus:outline-none focus-visible:ring-0"
|
||||
onClick={() => setHideField(true)}
|
||||
title="Hide field"
|
||||
>
|
||||
<EyeOffIcon className="h-3 w-3" />
|
||||
</button>
|
||||
<div className="flex items-center gap-3 border-border/50 border-t bg-muted/50 px-3 py-2.5">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="truncate font-medium text-xs">{field.recipient.name || field.recipient.email}</p>
|
||||
|
||||
{!isTemplateRecipientEmailPlaceholder(field.recipient.email) && field.recipient.name && (
|
||||
<p className="truncate text-muted-foreground text-xs">{field.recipient.email}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="-m-1 shrink-0 rounded-sm p-1 text-muted-foreground hover:bg-background hover:text-foreground"
|
||||
onClick={() => setHideField(true)}
|
||||
title={t`Hide field`}
|
||||
>
|
||||
<EyeOffIcon className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</PopoverHover>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user