Atlas Forms
Complete Library Examples
Three complete action library implementations showing real patterns: a CRM account linker, a workflow approval handler, and a bulk-export handler. Each example demonstrates the full lifecycle from handler to registration to schema usage.
Example 1: CRM Account Linker
Links a form record to a CRM account record by creating a cross-system relationship.
// handlers/linkCrmAccount.ts
import type { FormActionContext } from '@atlas-forms/types-js';
import { crmApi } from '../api/crmApi';
export const linkCrmAccountHandler = async (ctx: FormActionContext): Promise<void> => {
const { formValues, tenantId, config } = ctx;
const formRecordId = formValues['record-id'];
const crmAccountId = formValues['crm-account-id'];
if (!crmAccountId) {
ctx.fail('Please select a CRM account first.');
return;
}
try {
await crmApi.linkRecord({
tenantId,
formId: ctx.formId,
formRecordId,
crmAccountId,
linkType: config?.linkType ?? 'associated'
});
ctx.formEngine.setFieldValue('crm-link-status', 'linked');
ctx.complete('CRM account linked successfully.');
} catch (err) {
ctx.fail(`CRM link failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
}
};
// index.ts
export function registerCrmActions(): void {
registerFormAction('crm:link-account', linkCrmAccountHandler);
}
Example 2: Workflow Approval Handler
Approve or reject a workflow instance from a HIL form. Configurable outcome via handlerConfig.
// handlers/workflowApproval.ts
import type { FormActionContext } from '@atlas-forms/types-js';
import { workflowApi } from '../api/workflowApi';
export const workflowApprovalHandler = async (ctx: FormActionContext): Promise<void> => {
const { formValues, tenantId, config } = ctx;
const outcome = config?.outcome ?? 'approved';
const requireComment = config?.requireComment ?? false;
const instanceId = formValues['workflow-instance-id'];
const comment = formValues['approver-comment'];
if (!instanceId) { ctx.fail('Workflow instance not found.'); return; }
if (requireComment && !comment) { ctx.fail('A comment is required.'); return; }
try {
await workflowApi.transition({ instanceId, tenantId, outcome, comment });
ctx.complete(outcome === 'approved' ? 'Approved successfully.' : 'Rejected.');
ctx.navigate('/workdesk/inbox');
} catch (err) {
ctx.fail('Could not complete approval. Please try again.');
}
};
// Used in schema as:
// { "type": "custom", "label": "Approve", "config": { "handlerType": "hil:approve", "handlerConfig": { "outcome": "approved" } } }
// { "type": "custom", "label": "Reject", "config": { "handlerType": "hil:approve", "handlerConfig": { "outcome": "rejected", "requireComment": true } } }
Example 3: Bulk PDF Export
Generates a PDF from the form's current values and triggers a browser download.
// handlers/exportPdf.ts
import type { FormActionContext } from '@atlas-forms/types-js';
export const exportPdfHandler = async (ctx: FormActionContext): Promise<void> => {
const { formValues, formId, tenantId, config } = ctx;
const template = config?.template ?? 'default';
const filename = config?.filename ?? `form-${formId}.pdf`;
try {
const response = await fetch('/api/pdf/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ formId, tenantId, template, values: formValues })
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
ctx.complete('PDF downloaded.');
} catch (err) {
ctx.fail('PDF export failed. Please try again.');
}
};