/** * Settings tab for the form-builder. Surfaces non-definition settings * the parent `Form` row persists alongside the JSON definition: * * - allowedOrigins → array of hostnames the submit API accepts * - notifyEmails → mail recipients for new submissions * - webhookUrl → optional outbound webhook * - targetType → routing target (generic FormSubmission, CRM * contact, or entity-row) * - fieldMapping → field → target-column mapping for non-generic * target types * * Save semantics live with the parent route action — this is a * controlled view that emits onChange callbacks. */ import type * as React from "react"; import { useTranslation } from "react-i18next"; import type { FormField } from "@toolctrl/form-widget"; export type FormSettingsValue = { allowedOrigins: string[]; notifyEmails: string[]; webhookUrl: string; targetType: string; fieldMapping: Record; }; export type SettingsTabProps = { value: FormSettingsValue; fields: FormField[]; onChange: (next: FormSettingsValue) => void; }; const TARGET_OPTIONS = [ { value: "generic", labelKey: "settings.forms.builder.settings.targets.generic" }, { value: "crm-contact", labelKey: "settings.forms.builder.settings.targets.crmContact" }, { value: "entity-row", labelKey: "settings.forms.builder.settings.targets.entityRow" }, ]; function joinLines(values: string[]): string { return values.join("\n"); } function parseLines(raw: string): string[] { return raw .split(/\n+/u) .map((s) => s.trim()) .filter((s) => s.length > 0); } function parseCsvOrLines(raw: string): string[] { return raw .split(/[\n,]+/u) .map((s) => s.trim()) .filter((s) => s.length > 0); } export function SettingsTab({ value, fields, onChange }: SettingsTabProps): React.JSX.Element { const { t } = useTranslation(); const showMapping = value.targetType === "crm-contact" || value.targetType === "entity-row"; return (