mirror of
https://github.com/documenso/documenso.git
synced 2026-07-12 22:15:01 +10:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1aeb6325b0 | |||
| 2c1a18bafc | |||
| a2db5e9642 | |||
| 4ec9dc78c1 |
@@ -8,6 +8,61 @@ Check out what's new in the latest version and read our thoughts on it. For more
|
||||
|
||||
---
|
||||
|
||||
# Documenso v1.7.1: Signing order and document visibility
|
||||
|
||||
We're excited to introduce Documenso v1.7.1, bringing you improved control over your document signing process. Here are the key updates:
|
||||
|
||||
## 🌟 Key New Features
|
||||
|
||||
### 1. Signing Order
|
||||
|
||||
Specify the sequence in which recipients sign your documents. This ensures a structured signing process, particularly useful for complex agreements or hierarchical approvals.
|
||||
|
||||
<video
|
||||
src="/changelog/signing-order-demo.mp4"
|
||||
className="aspect-video w-full"
|
||||
autoPlay
|
||||
loop
|
||||
controls
|
||||
/>
|
||||
|
||||
### 2. Document Visibility
|
||||
|
||||
Manage who can view your documents and when. This feature offers greater privacy and flexibility in your document sharing workflows.
|
||||
|
||||
<video
|
||||
src="/changelog/document-visibility-demo.mp4"
|
||||
className="aspect-video w-full"
|
||||
autoPlay
|
||||
loop
|
||||
controls
|
||||
/>
|
||||
|
||||
## 🔧 Other Improvements
|
||||
|
||||
- Added language switcher for easier language selection
|
||||
- Support for smaller field bounds in documents
|
||||
- Improved select field UX
|
||||
- Enhanced template functionality for advanced fields
|
||||
- Added authOptions to the API
|
||||
- Various UI refinements and bug fixes
|
||||
|
||||
## 💡 Recent Features
|
||||
|
||||
Don't forget about these powerful features from our recent v1.7.0 release:
|
||||
|
||||
- Embedded Signing Experience
|
||||
- Copy and Paste Fields
|
||||
- Customizable Signature Colors
|
||||
|
||||
## 👏 Thank You
|
||||
|
||||
As always, we're grateful for our community's contributions and feedback. Your input continues to shape Documenso into the leading open-source document signing solution.
|
||||
|
||||
We're eager to see how these new features enhance your document workflows. Enjoy exploring Documenso v1.7.1!
|
||||
|
||||
---
|
||||
|
||||
# Documenso v1.7.0: Embedded Signing, Copy and Paste, and More
|
||||
|
||||
We're thrilled to announce the release of Documenso v1.7.0, packed with exciting new features and improvements that enhance document signing flexibility, user experience, and global accessibility.
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { useLingui } from '@lingui/react';
|
||||
|
||||
import { getRecipientType } from '@documenso/lib/client-only/recipient-type';
|
||||
import { RecipientStatusType, getRecipientType } from '@documenso/lib/client-only/recipient-type';
|
||||
import { RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
|
||||
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
|
||||
import type { DocumentStatus, Recipient } from '@documenso/prisma/client';
|
||||
@@ -29,24 +31,26 @@ export const StackAvatarsWithTooltip = ({
|
||||
const { _ } = useLingui();
|
||||
|
||||
const waitingRecipients = recipients.filter(
|
||||
(recipient) => getRecipientType(recipient) === 'waiting',
|
||||
(recipient) => getRecipientType(recipient) === RecipientStatusType.WAITING,
|
||||
);
|
||||
|
||||
const openedRecipients = recipients.filter(
|
||||
(recipient) => getRecipientType(recipient) === 'opened',
|
||||
(recipient) => getRecipientType(recipient) === RecipientStatusType.OPENED,
|
||||
);
|
||||
|
||||
const completedRecipients = recipients.filter(
|
||||
(recipient) => getRecipientType(recipient) === 'completed',
|
||||
(recipient) => getRecipientType(recipient) === RecipientStatusType.COMPLETED,
|
||||
);
|
||||
|
||||
const uncompletedRecipients = recipients.filter(
|
||||
(recipient) => getRecipientType(recipient) === 'unsigned',
|
||||
(recipient) => getRecipientType(recipient) === RecipientStatusType.UNSIGNED,
|
||||
);
|
||||
|
||||
const sortedRecipients = useMemo(() => recipients.sort((a, b) => a.id - b.id), [recipients]);
|
||||
|
||||
return (
|
||||
<PopoverHover
|
||||
trigger={children || <StackAvatars recipients={recipients} />}
|
||||
trigger={children || <StackAvatars recipients={sortedRecipients} />}
|
||||
contentProps={{
|
||||
className: 'flex flex-col gap-y-5 py-2',
|
||||
side: position,
|
||||
@@ -65,7 +69,7 @@ export const StackAvatarsWithTooltip = ({
|
||||
type={getRecipientType(recipient)}
|
||||
fallbackText={recipientAbbreviation(recipient)}
|
||||
/>
|
||||
<div className="">
|
||||
<div>
|
||||
<p className="text-muted-foreground text-sm">{recipient.email}</p>
|
||||
<p className="text-muted-foreground/70 text-xs">
|
||||
{_(RECIPIENT_ROLES_DESCRIPTION[recipient.role].roleName)}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import { getRecipientType } from '@documenso/lib/client-only/recipient-type';
|
||||
import {
|
||||
getExtraRecipientsType,
|
||||
getRecipientType,
|
||||
} from '@documenso/lib/client-only/recipient-type';
|
||||
import { recipientAbbreviation } from '@documenso/lib/utils/recipient-formatter';
|
||||
import type { Recipient } from '@documenso/prisma/client';
|
||||
|
||||
@@ -13,20 +16,27 @@ export function StackAvatars({ recipients }: { recipients: Recipient[] }) {
|
||||
const remainingItems = recipients.length - itemsToRender.length;
|
||||
|
||||
return itemsToRender.map((recipient: Recipient, index: number) => {
|
||||
const first = index === 0 ? true : false;
|
||||
const first = index === 0;
|
||||
|
||||
const lastItemText =
|
||||
index === itemsToRender.length - 1 && remainingItems > 0
|
||||
? `+${remainingItems + 1}`
|
||||
: undefined;
|
||||
if (index === 4 && remainingItems > 0) {
|
||||
return (
|
||||
<StackAvatar
|
||||
key="extra-recipient"
|
||||
first={first}
|
||||
zIndex={String(zIndex - index * 10)}
|
||||
type={getExtraRecipientsType(recipients.slice(4))}
|
||||
fallbackText={`+${remainingItems + 1}`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<StackAvatar
|
||||
key={recipient.id}
|
||||
first={first}
|
||||
zIndex={String(zIndex - index * 10)}
|
||||
type={lastItemText && index === 4 ? 'unsigned' : getRecipientType(recipient)}
|
||||
fallbackText={lastItemText ? lastItemText : recipientAbbreviation(recipient)}
|
||||
type={getRecipientType(recipient)}
|
||||
fallbackText={recipientAbbreviation(recipient)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
/bin/
|
||||
/node_modules/
|
||||
@@ -0,0 +1,2 @@
|
||||
config:
|
||||
gcp:project: scratchpad-438301
|
||||
@@ -0,0 +1,10 @@
|
||||
name: gcloud
|
||||
runtime:
|
||||
name: nodejs
|
||||
options:
|
||||
packagemanager: npm
|
||||
description: documenso on google cloud
|
||||
config:
|
||||
app--url: 'https://app.documenso.com'
|
||||
app--smtp-from-name: 'Documenso'
|
||||
app--smtp-from-address: 'noreply@documenso.com'
|
||||
@@ -0,0 +1,418 @@
|
||||
import * as gcp from '@pulumi/gcp';
|
||||
import * as pulumi from '@pulumi/pulumi';
|
||||
import * as random from '@pulumi/random';
|
||||
|
||||
const config = new pulumi.Config();
|
||||
|
||||
// Storage Config
|
||||
const storageLocation = config.get('storage--location') || 'EU';
|
||||
const serviceLocation = config.get('service--location') || 'europe-west3';
|
||||
|
||||
// KMS Config
|
||||
const algorithm = config.get('kms--algorithm') || 'RSA_SIGN_PKCS1_4096_SHA256';
|
||||
|
||||
// Database Config
|
||||
const databasePassword = config.get('db--password') || 'password';
|
||||
|
||||
// App Config
|
||||
// App Config
|
||||
const appUrl = config.require('app--url');
|
||||
const nextAuthSecret =
|
||||
config.getSecret('app--nextauth-secret') ||
|
||||
new random.RandomString('next-auth-secret', {
|
||||
length: 32,
|
||||
}).result;
|
||||
const encryptionKey =
|
||||
config.getSecret('app--encryption-key') ||
|
||||
new random.RandomString('encryption-key', {
|
||||
length: 32,
|
||||
}).result;
|
||||
const encryptionSecondaryKey =
|
||||
config.getSecret('app--encryption-secondary-key') ||
|
||||
new random.RandomString('encryption-secondary-key', {
|
||||
length: 32,
|
||||
}).result;
|
||||
const googleClientId = config.get('app--google-client-id') || '';
|
||||
const googleClientSecret = config.get('app--google-client-secret') || '';
|
||||
const oidcWellKnown = config.get('app--oidc-well-known') || '';
|
||||
const oidcClientId = config.get('app--oidc-client-id') || '';
|
||||
const oidcClientSecret = config.get('app--oidc-client-secret') || '';
|
||||
const oidcProviderLabel = config.get('app--oidc-provider-label') || 'OIDC';
|
||||
const oidcAllowSignup = config.get('app--oidc-allow-signup') || '';
|
||||
const oidcSkipVerify = config.get('app--oidc-skip-verify') || '';
|
||||
const internalWebappUrl = config.get('app--internal-webapp-url') || '';
|
||||
const smtpTransport = config.get('app--smtp-transport') || 'smtp-auth';
|
||||
const smtpHost = config.get('app--smtp-host') || '';
|
||||
const smtpPort = config.get('app--smtp-port') || '';
|
||||
const smtpUsername = config.get('app--smtp-username') || '';
|
||||
const smtpPassword = config.getSecret('app--smtp-password') || '';
|
||||
const smtpApikeyUser = config.get('app--smtp-apikey-user') || '';
|
||||
const smtpApikey = config.getSecret('app--smtp-apikey') || '';
|
||||
const smtpSecure = config.get('app--smtp-secure') || '';
|
||||
const smtpUnsafeIgnoreTls = config.get('app--smtp-unsafe-ignore-tls') || '';
|
||||
const smtpFromName = config.require('app--smtp-from-name');
|
||||
const smtpFromAddress = config.require('app--smtp-from-address');
|
||||
const resendApiKey = config.getSecret('app--resend-api-key') || '';
|
||||
const documentSizeUploadLimit = config.get('app--document-size-upload-limit') || '50';
|
||||
const stripeApiKey = config.getSecret('app--stripe-api-key') || '';
|
||||
const stripeWebhookSecret = config.getSecret('app--stripe-webhook-secret') || '';
|
||||
const stripeEnterprisePlanMonthlyPriceId =
|
||||
config.get('app--stripe-enterprise-plan-monthly-price-id') || '';
|
||||
const jobsProvider = config.get('app--jobs-provider') || 'local';
|
||||
const triggerApiKey = config.get('app--trigger-api-key') || '';
|
||||
const triggerApiUrl = config.get('app--trigger-api-url') || '';
|
||||
const inngestEventKey = config.get('app--inngest-event-key') || '';
|
||||
const posthogKey = config.get('app--posthog-key') || '';
|
||||
const billingEnabled = config.get('app--billing-enabled') || 'false';
|
||||
|
||||
new gcp.projects.Service('cloud-kms-api', {
|
||||
project: gcp.config.project,
|
||||
service: 'cloudkms.googleapis.com',
|
||||
disableOnDestroy: false,
|
||||
});
|
||||
|
||||
new gcp.projects.Service('cloud-run-api', {
|
||||
project: gcp.config.project,
|
||||
service: 'run.googleapis.com',
|
||||
disableOnDestroy: false,
|
||||
});
|
||||
|
||||
new gcp.projects.Service('compute-api', {
|
||||
project: gcp.config.project,
|
||||
service: 'compute.googleapis.com',
|
||||
disableOnDestroy: false,
|
||||
});
|
||||
|
||||
const signupDisabled = config.get('app--signup-disabled') || 'false';
|
||||
|
||||
// Create a GCS bucket for storage
|
||||
const storageBucket = new gcp.storage.Bucket('documenso-storage', {
|
||||
name: 'documenso-storage',
|
||||
location: storageLocation,
|
||||
});
|
||||
|
||||
// Create a service account so we can create a HMAC key to use the S3-compatible storage
|
||||
// API
|
||||
const storageServiceAccount = new gcp.serviceaccount.Account('documenso-storage-sa', {
|
||||
accountId: 'documenso-storage-sa',
|
||||
displayName: 'Storage Service Account',
|
||||
});
|
||||
|
||||
const appServiceAccount = new gcp.serviceaccount.Account('documenso-app-sa', {
|
||||
accountId: 'documenso-app-sa',
|
||||
displayName: 'App Service Account',
|
||||
});
|
||||
|
||||
// Create the HMAC key for the storage service account
|
||||
const hmacKey = new gcp.storage.HmacKey('documenso-storage-key', {
|
||||
serviceAccountEmail: storageServiceAccount.email,
|
||||
});
|
||||
|
||||
// Create a Cloud HSM cluster
|
||||
const hsmCluster = new gcp.kms.KeyRing('hsm-keyring', {
|
||||
name: 'documenso-hsm-keyring',
|
||||
location: serviceLocation,
|
||||
});
|
||||
|
||||
const hsmKey = new gcp.kms.CryptoKey('hsm-key', {
|
||||
name: 'documenso-hsm-key',
|
||||
keyRing: hsmCluster.id,
|
||||
purpose: 'ASYMMETRIC_SIGN',
|
||||
versionTemplate: {
|
||||
algorithm,
|
||||
protectionLevel: 'HSM',
|
||||
},
|
||||
});
|
||||
|
||||
// Create the database
|
||||
const database = new gcp.sql.DatabaseInstance('documenso-db', {
|
||||
name: 'documenso-db',
|
||||
databaseVersion: 'POSTGRES_15',
|
||||
region: serviceLocation,
|
||||
settings: {
|
||||
tier: 'db-custom-2-4096',
|
||||
diskSize: 50,
|
||||
diskType: 'PD_SSD',
|
||||
diskAutoresize: true,
|
||||
ipConfiguration: {
|
||||
ipv4Enabled: true,
|
||||
},
|
||||
backupConfiguration: {
|
||||
enabled: true,
|
||||
startTime: '02:00',
|
||||
backupRetentionSettings: {
|
||||
retainedBackups: 30,
|
||||
},
|
||||
pointInTimeRecoveryEnabled: true,
|
||||
transactionLogRetentionDays: 7,
|
||||
},
|
||||
databaseFlags: [
|
||||
{ name: 'max_connections', value: '100' },
|
||||
{ name: 'log_min_duration_statement', value: '300' },
|
||||
],
|
||||
maintenanceWindow: {
|
||||
day: 7,
|
||||
hour: 3,
|
||||
},
|
||||
insightsConfig: {
|
||||
queryInsightsEnabled: true,
|
||||
queryStringLength: 1024,
|
||||
recordApplicationTags: true,
|
||||
recordClientAddress: true,
|
||||
},
|
||||
},
|
||||
deletionProtection: true,
|
||||
});
|
||||
|
||||
const user = new gcp.sql.User('documenso-db-user', {
|
||||
name: 'documenso',
|
||||
instance: database.name,
|
||||
password: databasePassword,
|
||||
});
|
||||
|
||||
// Build and deploy the containerized application using Cloud Run
|
||||
const appService = new gcp.cloudrun.Service('documenso-app', {
|
||||
name: 'documenso-app',
|
||||
location: serviceLocation,
|
||||
template: {
|
||||
metadata: {
|
||||
annotations: {
|
||||
'run.googleapis.com/cloudsql-instances': database.connectionName,
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
image: 'documenso/documenso:latest',
|
||||
resources: {
|
||||
limits: {
|
||||
memory: '4Gi',
|
||||
cpu: '4',
|
||||
},
|
||||
},
|
||||
ports: [{ containerPort: 3000 }],
|
||||
envs: [
|
||||
{
|
||||
name: 'NEXTAUTH_URL',
|
||||
value: appUrl,
|
||||
},
|
||||
{
|
||||
name: 'NEXTAUTH_SECRET',
|
||||
value: nextAuthSecret,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_ENCRYPTION_KEY',
|
||||
value: encryptionKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY',
|
||||
value: encryptionSecondaryKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_GOOGLE_CLIENT_ID',
|
||||
value: googleClientId,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_GOOGLE_CLIENT_SECRET',
|
||||
value: googleClientSecret,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_WELL_KNOWN',
|
||||
value: oidcWellKnown,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_CLIENT_ID',
|
||||
value: oidcClientId,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_CLIENT_SECRET',
|
||||
value: oidcClientSecret,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_PROVIDER_LABEL',
|
||||
value: oidcProviderLabel,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_ALLOW_SIGNUP',
|
||||
value: oidcAllowSignup,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_OIDC_SKIP_VERIFY',
|
||||
value: oidcSkipVerify,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_WEBAPP_URL',
|
||||
value: appUrl,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_INTERNAL_WEBAPP_URL',
|
||||
value: internalWebappUrl,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_DATABASE_URL',
|
||||
value: pulumi.interpolate`postgres://${user.name}:${user.password}@localhost:5432/documenso?host=/cloudsql/${database.connectionName}/`,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_DIRECT_DATABASE_URL',
|
||||
value: pulumi.interpolate`postgres://${user.name}:${user.password}@localhost:5432/documenso?host=/cloudsql/${database.connectionName}/`,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SIGNING_TRANSPORT',
|
||||
value: 'gcloud-hsm',
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SIGNING_GCLOUD_HSM_KEY_PATH',
|
||||
value: hsmKey.id,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_UPLOAD_TRANSPORT',
|
||||
value: 's3',
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_ENDPOINT',
|
||||
value: 'https://storage.googleapis.com',
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_FORCE_PATH_STYLE',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_REGION',
|
||||
value: 'auto',
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_BUCKET',
|
||||
value: storageBucket.name,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID',
|
||||
value: hmacKey.accessId,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY',
|
||||
value: hmacKey.secret,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_TRANSPORT',
|
||||
value: smtpTransport,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_HOST',
|
||||
value: smtpHost,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_PORT',
|
||||
value: smtpPort,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_USERNAME',
|
||||
value: smtpUsername,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_PASSWORD',
|
||||
value: smtpPassword,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_APIKEY_USER',
|
||||
value: smtpApikeyUser,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_APIKEY',
|
||||
value: smtpApikey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_SECURE',
|
||||
value: smtpSecure,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_UNSAFE_IGNORE_TLS',
|
||||
value: smtpUnsafeIgnoreTls,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_FROM_NAME',
|
||||
value: smtpFromName,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_SMTP_FROM_ADDRESS',
|
||||
value: smtpFromAddress,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_RESEND_API_KEY',
|
||||
value: resendApiKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_DOCUMENT_SIZE_UPLOAD_LIMIT',
|
||||
value: documentSizeUploadLimit,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_STRIPE_API_KEY',
|
||||
value: stripeApiKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET',
|
||||
value: stripeWebhookSecret,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_STRIPE_ENTERPRISE_PLAN_MONTHLY_PRICE_ID',
|
||||
value: stripeEnterprisePlanMonthlyPriceId,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_JOBS_PROVIDER',
|
||||
value: jobsProvider,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_TRIGGER_API_KEY',
|
||||
value: triggerApiKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_TRIGGER_API_URL',
|
||||
value: triggerApiUrl,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PRIVATE_INNGEST_EVENT_KEY',
|
||||
value: inngestEventKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_POSTHOG_KEY',
|
||||
value: posthogKey,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_FEATURE_BILLING_ENABLED',
|
||||
value: billingEnabled,
|
||||
},
|
||||
{
|
||||
name: 'NEXT_PUBLIC_DISABLE_SIGNUP',
|
||||
value: signupDisabled,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
timeoutSeconds: 3600,
|
||||
serviceAccountName: appServiceAccount.email,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Allow unauthenticated invocations
|
||||
const iam = new gcp.cloudrun.IamMember('documenso-app-invoker', {
|
||||
service: appService.name,
|
||||
location: appService.location,
|
||||
role: 'roles/run.invoker',
|
||||
member: 'allUsers',
|
||||
});
|
||||
|
||||
// Allow the Cloud Run service to use the HSM for signing
|
||||
const _cryptoKeyIAMBinding = new gcp.kms.CryptoKeyIAMBinding('cryptoKeyIAMBinding', {
|
||||
cryptoKeyId: hsmKey.id,
|
||||
role: 'roles/cloudkms.signerVerifier',
|
||||
members: [appServiceAccount.email.apply((email) => `serviceAccount:${email}`)],
|
||||
});
|
||||
|
||||
// Allow the Cloud Run service to access the GCS Bucket
|
||||
const _bucketIAMBinding = new gcp.storage.BucketIAMBinding('bucketIAMBinding', {
|
||||
bucket: storageBucket.name,
|
||||
role: 'roles/storage.objectAdmin',
|
||||
members: [appServiceAccount.email.apply((email) => `serviceAccount:${email}`)],
|
||||
});
|
||||
|
||||
export const serviceUrl = appService.statuses[0].url;
|
||||
Generated
+3631
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "gcloud",
|
||||
"description": "documenso on google cloud",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "*",
|
||||
"@pulumi/gcp": "7.8.0",
|
||||
"@pulumi/google-native": "0.31.1",
|
||||
"@pulumi/random": "^4.16.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"outDir": "bin",
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"pretty": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"."
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Generated
+2445
-133
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -59,7 +59,8 @@
|
||||
"name": "@documenso/root",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
"packages/*",
|
||||
"infra/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@documenso/pdf-sign": "^0.1.0",
|
||||
@@ -74,4 +75,4 @@
|
||||
"trigger.dev": {
|
||||
"endpointId": "documenso-app"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
import type { Recipient } from '@documenso/prisma/client';
|
||||
import { ReadStatus, RecipientRole, SendStatus, SigningStatus } from '@documenso/prisma/client';
|
||||
|
||||
export enum RecipientStatusType {
|
||||
COMPLETED = 'completed',
|
||||
OPENED = 'opened',
|
||||
WAITING = 'waiting',
|
||||
UNSIGNED = 'unsigned',
|
||||
}
|
||||
|
||||
export const getRecipientType = (recipient: Recipient) => {
|
||||
if (
|
||||
recipient.role === RecipientRole.CC ||
|
||||
(recipient.sendStatus === SendStatus.SENT && recipient.signingStatus === SigningStatus.SIGNED)
|
||||
) {
|
||||
return 'completed';
|
||||
return RecipientStatusType.COMPLETED;
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -14,12 +21,33 @@ export const getRecipientType = (recipient: Recipient) => {
|
||||
recipient.readStatus === ReadStatus.OPENED &&
|
||||
recipient.signingStatus === SigningStatus.NOT_SIGNED
|
||||
) {
|
||||
return 'opened';
|
||||
return RecipientStatusType.OPENED;
|
||||
}
|
||||
|
||||
if (recipient.sendStatus === 'SENT' && recipient.signingStatus === 'NOT_SIGNED') {
|
||||
return 'waiting';
|
||||
if (
|
||||
recipient.sendStatus === SendStatus.SENT &&
|
||||
recipient.signingStatus === SigningStatus.NOT_SIGNED
|
||||
) {
|
||||
return RecipientStatusType.WAITING;
|
||||
}
|
||||
|
||||
return 'unsigned';
|
||||
return RecipientStatusType.UNSIGNED;
|
||||
};
|
||||
|
||||
export const getExtraRecipientsType = (extraRecipients: Recipient[]) => {
|
||||
const types = extraRecipients.map((r) => getRecipientType(r));
|
||||
|
||||
if (types.includes(RecipientStatusType.UNSIGNED)) {
|
||||
return RecipientStatusType.UNSIGNED;
|
||||
}
|
||||
|
||||
if (types.includes(RecipientStatusType.OPENED)) {
|
||||
return RecipientStatusType.OPENED;
|
||||
}
|
||||
|
||||
if (types.includes(RecipientStatusType.WAITING)) {
|
||||
return RecipientStatusType.WAITING;
|
||||
}
|
||||
|
||||
return RecipientStatusType.COMPLETED;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-16 16:03\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -159,7 +159,7 @@ msgstr "Unterzeichner kann nicht entfernt werden"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:221
|
||||
#~ msgid "Cannot update signer because they have already signed a field"
|
||||
#~ msgstr ""
|
||||
#~ msgstr "Cannot update signer because they have already signed a field"
|
||||
|
||||
#: packages/lib/constants/recipient-roles.ts:17
|
||||
msgid "Cc"
|
||||
@@ -280,7 +280,7 @@ msgstr "E-Mail-Optionen"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:1082
|
||||
msgid "Empty field"
|
||||
msgstr ""
|
||||
msgstr "Leeres Feld"
|
||||
|
||||
#: packages/lib/constants/template.ts:8
|
||||
msgid "Enable Direct Link Signing"
|
||||
@@ -705,15 +705,15 @@ msgstr "Dieses Feld kann nicht geändert oder gelöscht werden. Wenn Sie den dir
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:1050
|
||||
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
|
||||
msgstr ""
|
||||
msgstr "Dieser Empfänger kann nicht mehr bearbeitet werden, da er ein Feld unterschrieben oder das Dokument abgeschlossen hat."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:195
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:165
|
||||
#~ msgid "This signer has already received the document."
|
||||
#~ msgstr "Dieser Unterzeichner hat das Dokument bereits erhalten."
|
||||
#~ msgstr "This signer has already received the document."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:194
|
||||
msgid "This signer has already signed the document."
|
||||
msgstr ""
|
||||
msgstr "Dieser Unterzeichner hat das Dokument bereits unterschrieben."
|
||||
|
||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
||||
msgid "This will override any global settings."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-16 14:04\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -387,7 +387,7 @@ msgstr "Unsere selbstgehostete Option ist ideal für kleine Teams und Einzelpers
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/open/data.ts:25
|
||||
#~ msgid "Part-Time"
|
||||
#~ msgstr "Teilzeit"
|
||||
#~ msgstr "Part-Time"
|
||||
|
||||
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:151
|
||||
msgid "Premium Profile Name"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: de\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-16 16:03\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -789,7 +789,7 @@ msgstr "Unterzeichnung abschließen"
|
||||
msgid "Complete Viewing"
|
||||
msgstr "Betrachten abschließen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:58
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:62
|
||||
#: apps/web/src/components/formatter/document-status.tsx:28
|
||||
msgid "Completed"
|
||||
msgstr "Abgeschlossen"
|
||||
@@ -2143,7 +2143,7 @@ msgstr "Sobald Sie den QR-Code gescannt oder den Code manuell eingegeben haben,
|
||||
msgid "Oops! Something went wrong."
|
||||
msgstr "Hoppla! Etwas ist schief gelaufen."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:97
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:101
|
||||
msgid "Opened"
|
||||
msgstr "Geöffnet"
|
||||
|
||||
@@ -3636,7 +3636,7 @@ msgstr "Unable to sign in"
|
||||
msgid "Unauthorized"
|
||||
msgstr "Unauthorized"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:112
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:116
|
||||
msgid "Uncompleted"
|
||||
msgstr "Uncompleted"
|
||||
|
||||
@@ -3848,7 +3848,7 @@ msgstr "Teams ansehen"
|
||||
msgid "Viewed"
|
||||
msgstr "Angesehen"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:82
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:86
|
||||
msgid "Waiting"
|
||||
msgstr "Warten"
|
||||
|
||||
|
||||
@@ -784,7 +784,7 @@ msgstr "Complete Signing"
|
||||
msgid "Complete Viewing"
|
||||
msgstr "Complete Viewing"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:58
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:62
|
||||
#: apps/web/src/components/formatter/document-status.tsx:28
|
||||
msgid "Completed"
|
||||
msgstr "Completed"
|
||||
@@ -2138,7 +2138,7 @@ msgstr "Once you have scanned the QR code or entered the code manually, enter th
|
||||
msgid "Oops! Something went wrong."
|
||||
msgstr "Oops! Something went wrong."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:97
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:101
|
||||
msgid "Opened"
|
||||
msgstr "Opened"
|
||||
|
||||
@@ -3631,7 +3631,7 @@ msgstr "Unable to sign in"
|
||||
msgid "Unauthorized"
|
||||
msgstr "Unauthorized"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:112
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:116
|
||||
msgid "Uncompleted"
|
||||
msgstr "Uncompleted"
|
||||
|
||||
@@ -3843,7 +3843,7 @@ msgstr "View teams"
|
||||
msgid "Viewed"
|
||||
msgstr "Viewed"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:82
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:86
|
||||
msgid "Waiting"
|
||||
msgstr "Waiting"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-19 09:18\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
@@ -157,6 +157,10 @@ msgstr "Annuler"
|
||||
msgid "Cannot remove signer"
|
||||
msgstr "Impossible de retirer le signataire"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:221
|
||||
#~ msgid "Cannot update signer because they have already signed a field"
|
||||
#~ msgstr "Cannot update signer because they have already signed a field"
|
||||
|
||||
#: packages/lib/constants/recipient-roles.ts:17
|
||||
msgid "Cc"
|
||||
msgstr "Cc"
|
||||
@@ -276,7 +280,7 @@ msgstr "Options d'email"
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:1082
|
||||
msgid "Empty field"
|
||||
msgstr ""
|
||||
msgstr "Champ vide"
|
||||
|
||||
#: packages/lib/constants/template.ts:8
|
||||
msgid "Enable Direct Link Signing"
|
||||
@@ -701,15 +705,15 @@ msgstr "Ce champ ne peut pas être modifié ou supprimé. Lorsque vous partagez
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-fields.tsx:1050
|
||||
msgid "This recipient can no longer be modified as they have signed a field, or completed the document."
|
||||
msgstr ""
|
||||
msgstr "Ce destinataire ne peut plus être modifié car il a signé un champ ou complété le document."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:195
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:165
|
||||
#~ msgid "This signer has already received the document."
|
||||
#~ msgstr "Ce signataire a déjà reçu le document."
|
||||
#~ msgstr "This signer has already received the document."
|
||||
|
||||
#: packages/ui/primitives/document-flow/add-signers.tsx:194
|
||||
msgid "This signer has already signed the document."
|
||||
msgstr ""
|
||||
msgstr "Ce signataire a déjà signé le document."
|
||||
|
||||
#: packages/ui/components/recipient/recipient-action-auth-select.tsx:48
|
||||
msgid "This will override any global settings."
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-19 09:18\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
@@ -387,7 +387,7 @@ msgstr "Notre option auto-hébergée est idéale pour les petites équipes et le
|
||||
|
||||
#: apps/marketing/src/app/(marketing)/open/data.ts:25
|
||||
#~ msgid "Part-Time"
|
||||
#~ msgstr "Temps partiel"
|
||||
#~ msgstr "Part-Time"
|
||||
|
||||
#: apps/marketing/src/components/(marketing)/pricing-table.tsx:151
|
||||
msgid "Premium Profile Name"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: fr\n"
|
||||
"Project-Id-Version: documenso-app\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2024-09-19 09:18\n"
|
||||
"PO-Revision-Date: 2024-10-08 12:05\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
@@ -789,7 +789,7 @@ msgstr "Compléter la signature"
|
||||
msgid "Complete Viewing"
|
||||
msgstr "Compléter la visualisation"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:58
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:62
|
||||
#: apps/web/src/components/formatter/document-status.tsx:28
|
||||
msgid "Completed"
|
||||
msgstr "Complété"
|
||||
@@ -2143,7 +2143,7 @@ msgstr "Une fois que vous avez scanné le code QR ou saisi le code manuellement,
|
||||
msgid "Oops! Something went wrong."
|
||||
msgstr "Oups ! Quelque chose a mal tourné."
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:97
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:101
|
||||
msgid "Opened"
|
||||
msgstr "Ouvert"
|
||||
|
||||
@@ -3636,7 +3636,7 @@ msgstr "Impossible de se connecter"
|
||||
msgid "Unauthorized"
|
||||
msgstr "Non autorisé"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:112
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:116
|
||||
msgid "Uncompleted"
|
||||
msgstr "Non complet"
|
||||
|
||||
@@ -3848,7 +3848,7 @@ msgstr "Voir les équipes"
|
||||
msgid "Viewed"
|
||||
msgstr "Vu"
|
||||
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:82
|
||||
#: apps/web/src/components/(dashboard)/avatar/stack-avatars-with-tooltip.tsx:86
|
||||
msgid "Waiting"
|
||||
msgstr "En attente"
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"extends": "./packages/tsconfig/base.json",
|
||||
"include": ["packages/**/*", "apps/**/*"]
|
||||
}
|
||||
"include": [
|
||||
"packages/**/*",
|
||||
"apps/**/*",
|
||||
"infra/**/*"
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user