Docyrus

Record PDF Export

A three-step wizard (Select a Template → Preview → PDF) that renders a Docyrus data source record to PDF using its saved HTML templates, with an optional editable-template mode.

Client Only

Record PDF Export turns a single Docyrus data source record into a PDF through a guided three-step wizard:

  1. Select a Template — lists the data source's saved HTML/PDF templates (tenant_html_template).
  2. Preview — renders the chosen template compiled against the record, using the HtmlTemplateEditor in preview-only mode.
  3. PDF — generates the final PDF server-side and shows it in an inline viewer with a download button.
  4. Email (optional, when sendEmail is set) — mounts an email composer (useDocyrusEmailComposer) with the generated PDF pre-attached, so the user can send the record straight from the wizard.

The headless useDocyrusRecordPdfExport hook owns all data fetching, step state, and PDF generation. DocyrusRecordPdfExportWizard is the batteries-included UI built on top of it. The hook accepts a dataSourceId and recordId — the app / data source slugs needed by the render endpoints are resolved automatically (or supplied explicitly).

This is a Docyrus-connection component. It needs an authenticated RestApiClient to list templates, load the record, and render the PDF, so the preview above is informational only — wire it against your tenant (or the playground) to see it live.

Installation

pnpm dlx @docyrus/cli add @docyrus/ui-record-pdf-export
Required Packages(2 packages)
pnpm add @tanstack/react-query @docyrus/api-client

Usage

Wizard inside a dialog

import { useState } from 'react';

import { useDocyrusAuth } from '@docyrus/signin';
import { DocyrusRecordPdfExportWizard } from '@docyrus/ui/components/record-pdf-export';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogTrigger
} from '@docyrus/ui/primitives/ui/dialog';
import { Button } from '@docyrus/ui/primitives/ui/button';

function ExportRecordButton({ dataSourceId, recordId }: { dataSourceId: string; recordId: string }) {
  const { client } = useDocyrusAuth();
  const [open, setOpen] = useState(false);

  if (!client) return null;

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button variant="outline">Export to PDF</Button>
      </DialogTrigger>
      <DialogContent className="max-w-4xl">
        <DialogHeader>
          <DialogTitle>Export record to PDF</DialogTitle>
        </DialogHeader>
        <DocyrusRecordPdfExportWizard
          client={client}
          dataSourceId={dataSourceId}
          recordId={recordId}
          onClose={() => setOpen(false)}
        />
      </DialogContent>
    </Dialog>
  );
}

Editable-template mode

Pass templateEditable to let the user tweak the rendered document before exporting. The preview step then exposes the Code, Data (read-only reference), and Preview tabs — the Code tab holds the server-compiled document HTML for this record. When it is edited, the PDF step renders the edited HTML through the custom-body endpoint instead of the saved template.

<DocyrusRecordPdfExportWizard
  client={client}
  dataSourceId={dataSourceId}
  recordId={recordId}
  templateEditable
/>

Email step

Pass sendEmail to append an Email step. After the PDF is generated, the wizard mounts an email composer (via useDocyrusEmailComposer) with the rendered PDF pre-attached (sent through its storage path) and the user's email accounts loaded into the From selector. Sending requires the Messaging.Email.Send OAuth scope.

<DocyrusRecordPdfExportWizard
  client={client}
  dataSourceId={dataSourceId}
  recordId={recordId}
  sendEmail
/>

Headless — drive your own UI

import { HtmlTemplateEditor } from '@docyrus/ui/components/html-template-editor';
import { useDocyrusRecordPdfExport } from '@docyrus/ui/components/record-pdf-export';

function CustomExport({ client, dataSourceId, recordId }) {
  const {
    step, goNext, goBack, canGoNext,
    templates, selectedTemplateId, setSelectedTemplateId,
    previewEditorProps,
    pdfUrl, isGeneratingPdf
  } = useDocyrusRecordPdfExport({ client, dataSourceId, recordId });

  // Step 1 — render `templates` and call `setSelectedTemplateId(id)`.
  // Step 2 — <HtmlTemplateEditor {...previewEditorProps} />
  // Step 3 — <iframe src={pdfUrl} /> (auto-generated on entering the step).
}

How it works

StepEndpoint(s)Notes
Resolve slugsGET /v1/dev/data-sources/:dataSourceIdMaps dataSourceId → app_slug + slug. Skipped when appSlug + dataSourceSlug are supplied.
List templatesGET /v1/dev/html-templates?tenantDataSourceId=:dataSourceIdDrives the "Select a Template" step. The default template (is_default) is auto-selected.
Compiled previewGET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/templates/:templateId/htmlReturns the server-compiled document body (+ styles) for this record — the same templateCompiler the PDF uses. This is the preview source, so the preview matches the PDF exactly.
Record data (editable only)GET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId?columns=*Read-only reference shown in the editable-mode Data tab.
Render PDF (saved)GET /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/templates/:templateId/pdfDefault path. The server compiles the saved template against the record.
Render PDF (edited)PUT /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:recordId/renderPdfTemplate/:templateIdUsed in templateEditable mode when the compiled HTML was edited. Sends the edited HTML as a multipart/form-data body file (data={} so the server loads the record for header/footer).

All render endpoints require the bearer token to carry a DS.Read.{Slug} (or DS.ReadWrite.{Slug}) scope for the target data source. The render result is returned under the response data as { id, path, fullPath, url? }. When the backend includes a signed/public url, the PDF step renders it inline with a Download button; otherwise it shows a "generated" confirmation with the filename.

Preview uses the HTML Template Editor

The preview step mounts HtmlTemplateEditor with the server-compiled document HTML as value, then restricts the visible tabs. Compiling on the server (rather than client-compiling the raw template against the raw record) is what makes the preview faithful — the record's fields are mapped/expanded exactly as they are for the PDF. Three editor props power this:

PropTypePurpose
visibleTabsHtmlTemplateEditorTab[]Restricts which tabs render (and their order). The wizard passes ['preview'] (read-only) or ['code', 'data', 'preview'] (editable). The tab strip auto-hides when a single tab remains, and the Visual/Plate tab is intentionally omitted (its round-trip is lossy for complex nested-block table templates).
dataReadOnlybooleanMakes only the Data tab read-only while keeping the Code editor editable — the record data is a reference, not editable.
previewStylesstringExtra CSS injected into the Preview iframe (the template's styles), without baking a <style> block into the Plate document tree.

In editable mode the user tweaks the compiled document HTML (the final output for this record) in the Code tab — the custom-body PDF endpoint takes final HTML as-is, so this is the only round-trip-faithful editing surface the API supports.

Hook — useDocyrusRecordPdfExport

const wizard = useDocyrusRecordPdfExport(options);

Options

OptionTypeDefaultDescription
clientRestApiClient—Authenticated REST client.
dataSourceIdstring—tenant_data_source.id of the record's data source.
recordIdstring—tenant_data_source_item.id of the record to render.
appSlugstring—App slug. When omitted, resolved from dataSourceId.
dataSourceSlugstring—Data source slug. When omitted, resolved from dataSourceId.
enabledbooleantrueToggles all network activity.
templateEditablebooleanfalseExposes template + read-only Data tabs in the preview; edited bodies render via the custom-body endpoint.
sendEmailbooleanfalseAppends an Email step that mounts a composer with the generated PDF pre-attached. Sending needs the Messaging.Email.Send scope.
initialTemplateIdstring—Pre-select a template by id.
autoSelectDefaultTemplatebooleantrueAuto-select the default (or first) template once the list resolves.
resolveDataSourceEndpointstring/v1/dev/data-sources/{id}Endpoint override for slug resolution.
listTemplatesEndpointstring/v1/dev/html-templatesEndpoint override for the templates list.
templateDetailEndpointstring/v1/dev/html-templates/{templateId}Endpoint override for a template's body.

Returns

FieldTypeDescription
stepsRecordPdfExportStep[]Ordered steps for this wizard — includes 'email' when sendEmail is set.
step / setStep / stepIndexRecordPdfExportStep …Current step ('select' | 'preview' | 'pdf' | 'email') and controls.
goNext / goBack / canGoNext / canGoBack / isLastStep—Step navigation.
appSlug / dataSourceSlug / isResolving / resolveError—Resolved slugs + resolution state.
templates / isLoadingTemplates / templatesError / refetchTemplates—Templates list state.
selectedTemplateId / setSelectedTemplateId / selectedTemplate—Selected template.
templateDetail / isLoadingTemplateDetail / templateDetailErrorDocyrusHtmlTemplateDetail …Selected template's body / styles.
record / recordJson / isLoadingRecord / recordError—The target record (object + pretty JSON string).
templateEditable / editedHtml / setEditedHtml / isDirty / resetEdits—Editable body state.
generatePdf / isGeneratingPdf / pdfResult / pdfUrl / pdfError—PDF generation. Auto-fires on entering the PDF step.
previewEditorPropsRecordPdfExportPreviewEditorPropsReady to spread onto <HtmlTemplateEditor> for the preview step.
reset() => voidReset the wizard back to the first step.

API Reference — DocyrusRecordPdfExportWizard

Extends every hook option plus:

PropTypeDefaultDescription
classNamestring—Wrapper class.
bodyHeightstring'70vh'Height of the wizard body region.
onClose() => void—Fired by the footer Done button on the PDF step.
hideClosebooleanfalseHide the footer Done button.

Type Exports

TypeDescription
UseDocyrusRecordPdfExportOptionsOptions for the hook.
UseDocyrusRecordPdfExportResultReturn shape of the hook.
RecordPdfExportPreviewEditorPropsProps spread onto HtmlTemplateEditor for the preview.
DocyrusRecordPdfExportWizardPropsProps for the wizard component.
DocyrusHtmlTemplateSummaryTemplate list row.
DocyrusHtmlTemplateDetailTemplate detail row (adds body / styles).
DocyrusRecordPdfResultThe upstream html-to-pdf result (url, filename, …).
RecordPdfExportStep'select' | 'preview' | 'pdf'.

On this page