import React, { useEffect, useState } from 'react';
import {
Accordion,
AccordionControl,
AccordionItem,
AccordionPanel,
Alert,
Box,
Button,
Checkbox,
Flex,
Group,
Modal,
Select,
SimpleGrid,
Stack,
Tabs,
TabsList,
TabsPanel,
TabsTab,
Text,
Textarea,
TextInput,
} from '@mantine/core';
import { isNotEmpty, useForm } from '@mantine/form';
import {
buildConfig,
buildSubscriptions,
createConnectIntegration,
EVENT_OPTIONS,
parseApiError,
setConnectSubscriptions,
updateConnectIntegration,
} from '../../utils/forms/ConnectionUtils.js';
const PayloadTemplateItem = ({ opt, payloadTemplates, onTemplateChange }) => (
{opt.label}
);
const HeaderRow = ({ h, onKeyChange, onValueChange, onRemove }) => (
);
const ConnectionForm = ({ connection = null, isOpen, onClose }) => {
const [submitting, setSubmitting] = useState(false);
const [selectedEvents, setSelectedEvents] = useState([]);
const [headers, setHeaders] = useState([]);
const [payloadTemplates, setPayloadTemplates] = useState({});
const [apiError, setApiError] = useState('');
// One-time form
const form = useForm({
mode: 'controlled',
initialValues: {
name: connection?.name || '',
type: connection?.type || 'webhook',
url: connection?.config?.url || '',
script_path: connection?.config?.path || '',
enabled: connection?.enabled ?? true,
},
validate: {
name: isNotEmpty('Provide a name'),
type: isNotEmpty('Select a type'),
url: (value, values) => {
if (values.type === 'webhook' && !value.trim()) {
return 'Provide a webhook URL';
}
return null;
},
script_path: (value, values) => {
if (values.type === 'script' && !value.trim()) {
return 'Provide a script path';
}
return null;
},
},
});
useEffect(() => {
if (connection) {
const values = {
name: connection.name,
type: connection.type,
url: connection.config?.url,
script_path: connection.config?.path,
enabled: connection.enabled,
};
form.setValues(values);
setSelectedEvents(
connection.subscriptions.reduce((acc, sub) => {
if (sub.enabled) acc.push(sub.event);
return acc;
}, [])
);
// Initialize headers array from config.headers object
const cfgHeaders = connection.config?.headers || {};
const hdrs = Object.keys(cfgHeaders).length
? Object.entries(cfgHeaders).map(([k, v]) => ({ key: k, value: v }))
: [{ key: '', value: '' }];
setHeaders(hdrs);
// Initialize payload templates per subscription
const templates = {};
connection.subscriptions.forEach((sub) => {
if (sub.payload_template) templates[sub.event] = sub.payload_template;
});
setPayloadTemplates(templates);
} else {
form.reset();
setSelectedEvents([]);
setHeaders([{ key: '', value: '' }]);
setPayloadTemplates({});
}
}, [connection]);
const handleClose = () => {
setApiError('');
onClose?.();
};
const onSubmit = async (values) => {
setSubmitting(true);
setApiError('');
try {
const config = buildConfig(values, headers);
const subs = buildSubscriptions(selectedEvents, payloadTemplates);
if (connection) {
await updateConnectIntegration(connection, values, config);
} else {
connection = await createConnectIntegration(values, config);
}
await setConnectSubscriptions(connection, subs);
handleClose();
} catch (error) {
console.error('Failed to create/update connection', error);
const { fieldErrors, apiError } = parseApiError(error);
if (Object.keys(fieldErrors).length > 0) form.setErrors(fieldErrors);
setApiError(apiError);
} finally {
setSubmitting(false);
}
};
const toggleEvent = (event) => {
setSelectedEvents((prev) =>
prev.includes(event) ? prev.filter((e) => e !== event) : [...prev, event]
);
};
if (!isOpen) return null;
const onHeaderKeyChange = (idx, newValue) => {
const next = [...headers];
next[idx] = { ...next[idx], key: newValue };
setHeaders(next);
};
const onHeaderValueChange = (idx, newValue) => {
const next = [...headers];
next[idx] = {
...next[idx],
value: newValue,
};
setHeaders(next);
};
const onHeaderRemove = (idx) => {
const next = headers.filter((_, i) => i !== idx);
setHeaders(next.length ? next : [{ key: '', value: '' }]);
};
return (
);
};
export default ConnectionForm;