Compare commits

..

2 Commits

Author SHA1 Message Date
ephraimduncan 9e73e55953 Merge remote-tracking branch 'origin/main' into pr-2848
# Conflicts:
#	packages/lib/constants/app.ts
2026-07-02 06:48:01 +00:00
ephraimduncan beea267910 feat: allow signing reason override 2026-05-21 03:49:00 +00:00
11 changed files with 33 additions and 26 deletions
+2
View File
@@ -80,6 +80,8 @@ NEXT_PRIVATE_SIGNING_CSC_OAUTH_CLIENT_SECRET=
NEXT_PRIVATE_SIGNING_CSC_SIGNATURE_LEVEL=
# OPTIONAL: Comma-separated list of timestamp authority URLs for PDF signing (enables LTV and archival timestamps).
NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY=
# OPTIONAL: Reason to embed in PDF signatures. Defaults to "Signed by Documenso".
NEXT_PRIVATE_SIGNING_REASON=
# OPTIONAL: Contact info to embed in PDF signatures. Defaults to the webapp URL.
NEXT_PUBLIC_SIGNING_CONTACT_INFO=
# OPTIONAL: Set to "true" to use the legacy adbe.pkcs7.detached subfilter instead of ETSI.CAdES.detached.
@@ -1,6 +1,5 @@
import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth';
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
import { isFieldUnsignedAndRequired } from '@documenso/lib/utils/advanced-fields-helpers';
import type { FieldWithSignature } from '@documenso/prisma/types/field-with-signature';
import { FieldRootContainer } from '@documenso/ui/components/field/field';
import { getRecipientColorStyles } from '@documenso/ui/lib/recipient-colors';
@@ -118,12 +117,7 @@ export const DocumentSigningFieldContainer = ({
};
return (
<FieldRootContainer
color={getRecipientColorStyles(
field.fieldMeta?.readOnly ? 'readOnly' : isFieldUnsignedAndRequired(field) ? 'required' : 0,
)}
field={field}
>
<FieldRootContainer color={getRecipientColorStyles(field.fieldMeta?.readOnly ? 'readOnly' : 0)} field={field}>
{!field.inserted && !loading && !readOnlyField && (
<button
type="submit"
@@ -152,13 +152,7 @@ export const EnvelopeSignerPageRenderer = ({ pageData }: { pageData: PageRenderD
const isValidating = showPendingFieldTooltip && isFieldUnsignedAndRequired(fieldToRender);
const color = fieldToRender.fieldMeta?.readOnly
? 'readOnly'
: isValidating
? 'orange'
: isFieldUnsignedAndRequired(fieldToRender)
? 'required'
: 'green';
const color = fieldToRender.fieldMeta?.readOnly ? 'readOnly' : isValidating ? 'orange' : 'green';
const { fieldGroup } = renderField({
scale,
+21
View File
@@ -0,0 +1,21 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import { NEXT_PRIVATE_SIGNING_REASON } from './app';
describe('NEXT_PRIVATE_SIGNING_REASON', () => {
afterEach(() => {
vi.unstubAllEnvs();
});
it('defaults to the Documenso signing reason', () => {
vi.stubEnv('NEXT_PRIVATE_SIGNING_REASON', undefined);
expect(NEXT_PRIVATE_SIGNING_REASON()).toBe('Signed by Documenso');
});
it('uses the configured signing reason verbatim', () => {
vi.stubEnv('NEXT_PRIVATE_SIGNING_REASON', 'Signed by Objective');
expect(NEXT_PRIVATE_SIGNING_REASON()).toBe('Signed by Objective');
});
});
+1
View File
@@ -35,6 +35,7 @@ export const IS_AI_FEATURES_CONFIGURED = () => !!env('GOOGLE_VERTEX_PROJECT_ID')
export const NEXT_PRIVATE_USE_PLAYWRIGHT_PDF = () => env('NEXT_PRIVATE_USE_PLAYWRIGHT_PDF') === 'true';
export const NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY = () => env('NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY');
export const NEXT_PRIVATE_SIGNING_REASON = () => env('NEXT_PRIVATE_SIGNING_REASON') ?? 'Signed by Documenso';
/**
* Whether this Documenso instance is running in CSC (Cloud Signature Consortium) mode.
+2 -1
View File
@@ -1,4 +1,5 @@
import {
NEXT_PRIVATE_SIGNING_REASON,
NEXT_PRIVATE_USE_LEGACY_SIGNING_SUBFILTER,
NEXT_PUBLIC_SIGNING_CONTACT_INFO,
NEXT_PUBLIC_WEBAPP_URL,
@@ -42,7 +43,7 @@ export const signPdf = async ({ pdf }: SignOptions) => {
const { bytes } = await pdf.sign({
signer,
reason: 'Signed by Documenso',
reason: NEXT_PRIVATE_SIGNING_REASON(),
location: NEXT_PUBLIC_WEBAPP_URL(),
contactInfo: NEXT_PUBLIC_SIGNING_CONTACT_INFO(),
subFilter: NEXT_PRIVATE_USE_LEGACY_SIGNING_SUBFILTER() ? 'adbe.pkcs7.detached' : 'ETSI.CAdES.detached',
-1
View File
@@ -116,7 +116,6 @@ module.exports = {
orange: 'hsl(var(--recipient-orange))',
yellow: 'hsl(var(--recipient-yellow))',
pink: 'hsl(var(--recipient-pink))',
red: 'hsl(var(--recipient-red))',
},
},
backgroundImage: {
+1
View File
@@ -59,6 +59,7 @@ declare namespace NodeJS {
NEXT_PRIVATE_SIGNING_CSC_OAUTH_CLIENT_SECRET?: string;
NEXT_PRIVATE_SIGNING_CSC_SIGNATURE_LEVEL?: 'AES' | 'QES';
NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY?: string;
NEXT_PRIVATE_SIGNING_REASON?: string;
NEXT_PUBLIC_SIGNING_CONTACT_INFO?: string;
NEXT_PRIVATE_USE_LEGACY_SIGNING_SUBFILTER?: string;
+1 -1
View File
@@ -119,7 +119,7 @@ export function FieldRootContainer({ field, children, color, className, readonly
data-readonly={readonly ? 'true' : 'false'}
className={cn(
FIELD_ROOT_CONTAINER_CLASS_NAME,
!(isValidating && isFieldUnsignedAndRequired(field)) && color?.base,
color?.base,
{
'px-2': field.type !== FieldType.SIGNATURE && field.type !== FieldType.FREE_SIGNATURE,
'justify-center': !field.inserted,
+3 -8
View File
@@ -1,7 +1,7 @@
import { colord } from 'colord';
import { once } from 'remeda';
export type TRecipientColor = 'readOnly' | 'required' | (typeof AVAILABLE_RECIPIENT_COLORS)[number];
export type TRecipientColor = 'readOnly' | (typeof AVAILABLE_RECIPIENT_COLORS)[number];
export type RecipientColorStyles = {
base: string;
@@ -33,7 +33,6 @@ const RECIPIENT_COLOR_STYLES: Record<TRecipientColor, () => RecipientColorStyles
'ring-2 ring-recipient-green shadow-[0_0_0_5px_hsl(var(--recipient-green)/10%),0_0_0_2px_hsl(var(--recipient-green)/60%),0_0_0_0.5px_hsl(var(--recipient-green))]',
comboBoxItem: '',
}),
required: once(() => generateStyles('red')),
green: once(() => generateStyles('green')),
blue: once(() => generateStyles('blue')),
purple: once(() => generateStyles('purple')),
@@ -42,7 +41,7 @@ const RECIPIENT_COLOR_STYLES: Record<TRecipientColor, () => RecipientColorStyles
pink: once(() => generateStyles('pink')),
};
const generateStyles = (recipientColor: TCssVarRecipientColor): RecipientColorStyles => {
const generateStyles = (recipientColor: TRecipientColor): RecipientColorStyles => {
const { bg, border, ring, text } = CSS_PROPERTY;
const { active, hover, groupHover, groupHoverFieldItem } = CSS_VARIANT;
@@ -80,13 +79,9 @@ const CSS_VARIANT = {
const AVAILABLE_RECIPIENT_COLORS = ['green', 'blue', 'purple', 'orange', 'yellow', 'pink'] as const;
const CSS_VAR_RECIPIENT_COLORS = [...AVAILABLE_RECIPIENT_COLORS, 'red'] as const;
type TCssVarRecipientColor = (typeof CSS_VAR_RECIPIENT_COLORS)[number];
export const RECIPIENT_DYNAMIC_CLASS = {
pattern: new RegExp(
`(${Object.values(CSS_PROPERTY).join('|')})-recipient-(${CSS_VAR_RECIPIENT_COLORS.join('|')})(\\/(15|30))?$`,
`(${Object.values(CSS_PROPERTY).join('|')})-recipient-(${AVAILABLE_RECIPIENT_COLORS.join('|')})(\\/(15|30))?$`,
),
variants: Object.values(CSS_VARIANT),
};
-1
View File
@@ -55,7 +55,6 @@
--recipient-orange: 36 92% 54%;
--recipient-yellow: 51 100% 43%;
--recipient-pink: 313 65% 57%;
--recipient-red: 0 91% 71%;
/* Base - Neutral */
--new-neutral-50: 0, 0%, 96%;