feat: add organisation template type (#2611)

This commit is contained in:
Ephraim Duncan
2026-03-16 14:29:34 +00:00
committed by GitHub
parent 943a0b50e3
commit 36bbd97514
41 changed files with 1702 additions and 279 deletions
@@ -0,0 +1,76 @@
import React, { forwardRef } from 'react';
import { t } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';
import { TemplateType } from '@prisma/client';
import type { SelectProps } from '@radix-ui/react-select';
import { InfoIcon } from 'lucide-react';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@documenso/ui/primitives/select';
import { Tooltip, TooltipContent, TooltipTrigger } from '@documenso/ui/primitives/tooltip';
export type TemplateTypeSelectProps = SelectProps;
export const TemplateTypeSelect = forwardRef<HTMLButtonElement, TemplateTypeSelectProps>(
({ ...props }, ref) => {
useLingui();
return (
<Select {...props}>
<SelectTrigger ref={ref} className="bg-background">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value={TemplateType.PRIVATE}>{t`Private`}</SelectItem>
<SelectItem value={TemplateType.PUBLIC}>{t`Public`}</SelectItem>
<SelectItem value={TemplateType.ORGANISATION}>{t`Organisation`}</SelectItem>
</SelectContent>
</Select>
);
},
);
TemplateTypeSelect.displayName = 'TemplateTypeSelect';
export const TemplateTypeTooltip = ({
organisationTeamCount,
}: {
organisationTeamCount: number;
}) => {
return (
<Tooltip>
<TooltipTrigger>
<InfoIcon className="mx-2 h-4 w-4" />
</TooltipTrigger>
<TooltipContent className="max-w-md space-y-2 p-4 text-foreground">
<p>
<Trans>
<strong>Private</strong> templates can only be used by your team.
</Trans>
</p>
<p>
<Trans>
<strong>Public</strong> templates are linked to your public profile.
</Trans>
</p>
{organisationTeamCount >= 2 && (
<p>
<Trans>
<strong>Organisation</strong> templates are shared across all teams in your
organisation but can only be edited by the owning team.
</Trans>
</p>
)}
</TooltipContent>
</Tooltip>
);
};
+2
View File
@@ -20,6 +20,8 @@ const badgeVariants = cva(
'bg-green-50 text-green-700 ring-green-600/20 dark:bg-green-500/10 dark:text-green-400 dark:ring-green-500/20',
secondary:
'bg-blue-50 text-blue-700 ring-blue-700/10 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-blue-400/30',
orange:
'bg-orange-50 text-orange-700 ring-orange-700/10 dark:bg-orange-400/10 dark:text-orange-400 dark:ring-orange-400/30',
},
size: {
small: 'px-1.5 py-0.5 text-xs',
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import { Trans, useLingui } from '@lingui/react/macro';
import { DocumentVisibility, TeamMemberRole } from '@prisma/client';
import { DocumentVisibility, TeamMemberRole, TemplateType } from '@prisma/client';
import { DocumentDistributionMethod, type Field, type Recipient } from '@prisma/client';
import { InfoIcon } from 'lucide-react';
import { useForm } from 'react-hook-form';
@@ -36,6 +36,10 @@ import {
DocumentVisibilitySelect,
DocumentVisibilityTooltip,
} from '@documenso/ui/components/document/document-visibility-select';
import {
TemplateTypeSelect,
TemplateTypeTooltip,
} from '@documenso/ui/components/template/template-type-select';
import {
Accordion,
AccordionContent,
@@ -109,6 +113,7 @@ export const AddTemplateSettingsFormPartial = ({
defaultValues: {
title: template.title,
externalId: template.externalId || undefined,
templateType: template.type || TemplateType.PRIVATE,
visibility: template.visibility || '',
globalAccessAuth: documentAuthOption?.globalAccessAuth || [],
globalActionAuth: documentAuthOption?.globalActionAuth || [],
@@ -325,6 +330,29 @@ export const AddTemplateSettingsFormPartial = ({
/>
)}
<FormField
control={form.control}
name="templateType"
render={({ field }) => (
<FormItem>
<FormLabel className="flex flex-row items-center">
<Trans>Template type</Trans>
<TemplateTypeTooltip organisationTeamCount={organisation.teams.length} />
</FormLabel>
<FormControl>
<TemplateTypeSelect
{...field}
onValueChange={(value) => {
field.onChange(value);
void handleAutoSave();
}}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="meta.distributionMethod"
@@ -1,6 +1,6 @@
import { msg } from '@lingui/core/macro';
import { DocumentDistributionMethod } from '@prisma/client';
import { DocumentVisibility } from '@prisma/client';
import { DocumentVisibility, TemplateType } from '@prisma/client';
import { z } from 'zod';
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
@@ -21,6 +21,7 @@ import { isValidRedirectUrl } from '@documenso/lib/utils/is-valid-redirect-url';
export const ZAddTemplateSettingsFormSchema = z.object({
title: z.string().trim().min(1, { message: "Title can't be empty" }),
externalId: z.string().optional(),
templateType: z.nativeEnum(TemplateType).optional(),
visibility: z.nativeEnum(DocumentVisibility).optional(),
globalAccessAuth: z
.array(z.union([ZDocumentAccessAuthTypesSchema, z.literal('-1')]))