feat: allow creating embeds in folder (#2612)

## Description

Allow passing in a `folderId` when creating an embedded envelope 

## Embed repo changes here

https://github.com/documenso/embeds/pull/69/changes
This commit is contained in:
David Nguyen
2026-03-13 14:50:14 +11:00
committed by GitHub
parent 8d97f1dcfa
commit 2f2b5dd232
7 changed files with 486 additions and 213 deletions
@@ -115,9 +115,10 @@ const EnvelopeEditor = ({ presignToken, envelopeId }) => {
### Create Component Only
| Prop | Type | Required | Description |
| ------ | ------------------------------ | -------- | --------------------------------------------------- |
| `type` | `"DOCUMENT"` \| `"TEMPLATE"` | Yes | Whether to create a document or template envelope |
| Prop | Type | Required | Description |
| ---------- | ------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | `"DOCUMENT"` \| `"TEMPLATE"` | Yes | Whether to create a document or template envelope |
| `folderId` | `string` | No | The ID of the folder to create the envelope in. If not provided, the envelope is created in the root folder. The folder must match the envelope type and team. |
### Update Component Only
+38 -14
View File
@@ -36,6 +36,7 @@ export default function EmbedPlaygroundPage() {
const [envelopeType, setEnvelopeType] = useState<'DOCUMENT' | 'TEMPLATE'>(
() => (searchParams.get('envelopeType') as 'DOCUMENT' | 'TEMPLATE') || 'DOCUMENT',
);
const [folderId, setFolderId] = useState(() => searchParams.get('folderId') || '');
// Auto-launch if query params are present on mount
const [iframeSrc, setIframeSrc] = useState<string | null>(null);
@@ -201,6 +202,7 @@ export default function EmbedPlaygroundPage() {
mode: string;
envelopeId: string;
envelopeType: string;
folderId: string;
}) => {
const newParams = new URLSearchParams();
@@ -224,6 +226,10 @@ export default function EmbedPlaygroundPage() {
newParams.set('envelopeType', params.envelopeType);
}
if (params.folderId) {
newParams.set('folderId', params.folderId);
}
const qs = newParams.toString();
void navigate(qs ? `?${qs}` : '.', { replace: true });
@@ -263,6 +269,7 @@ export default function EmbedPlaygroundPage() {
const hashData = {
externalId: externalId || undefined,
type: mode === 'create' ? envelopeType : undefined,
folderId: mode === 'create' && folderId ? folderId : undefined,
darkModeDisabled: darkModeDisabled || undefined,
css: rawCss || undefined,
cssVars: Object.keys(filteredCssVars).length > 0 ? filteredCssVars : undefined,
@@ -292,7 +299,7 @@ export default function EmbedPlaygroundPage() {
setIframeSrc(buildIframeSrc(basePath, presignToken, hash));
setIframeKey((prev) => prev + 1);
updateQueryParams({ token: inputToken, externalId, mode, envelopeId, envelopeType });
updateQueryParams({ token: inputToken, externalId, mode, envelopeId, envelopeType, folderId });
};
const handleSubmit = useCallback(
@@ -306,6 +313,7 @@ export default function EmbedPlaygroundPage() {
mode,
envelopeId,
envelopeType,
folderId,
generalFeatures,
settingsFeatures,
actionsFeatures,
@@ -324,6 +332,7 @@ export default function EmbedPlaygroundPage() {
setMode('create');
setEnvelopeId('');
setEnvelopeType('DOCUMENT');
setFolderId('');
setIframeSrc(null);
setMessages([]);
setTokenError(null);
@@ -422,19 +431,34 @@ export default function EmbedPlaygroundPage() {
</div>
{mode === 'create' && (
<div style={{ marginBottom: '8px' }}>
<label style={{ display: 'block', fontSize: '12px', fontWeight: 'bold' }}>
Envelope Type
</label>
<select
value={envelopeType}
onChange={(e) => setEnvelopeType(e.target.value as 'DOCUMENT' | 'TEMPLATE')}
style={{ width: '100%', padding: '4px', fontSize: '12px' }}
>
<option value="DOCUMENT">Document</option>
<option value="TEMPLATE">Template</option>
</select>
</div>
<>
<div style={{ marginBottom: '8px' }}>
<label style={{ display: 'block', fontSize: '12px', fontWeight: 'bold' }}>
Envelope Type
</label>
<select
value={envelopeType}
onChange={(e) => setEnvelopeType(e.target.value as 'DOCUMENT' | 'TEMPLATE')}
style={{ width: '100%', padding: '4px', fontSize: '12px' }}
>
<option value="DOCUMENT">Document</option>
<option value="TEMPLATE">Template</option>
</select>
</div>
<div style={{ marginBottom: '8px' }}>
<label style={{ display: 'block', fontSize: '12px', fontWeight: 'bold' }}>
Folder ID (optional)
</label>
<input
type="text"
value={folderId}
onChange={(e) => setFolderId(e.target.value)}
style={{ width: '100%', padding: '4px', fontSize: '12px' }}
placeholder="folder cuid"
/>
</div>
</>
)}
{mode === 'edit' && (
@@ -358,7 +358,7 @@ const EnvelopeCreatePage = ({ embedAuthoringOptions }: EnvelopeCreatePageProps)
publicDescription: '',
userId: tokenUserId,
teamId: tokenTeamId,
folderId: null,
folderId: embedAuthoringOptions?.folderId ?? null,
documentMeta: {
id: '',
...defaultDocumentMeta,