import { Controller, FormProvider } from 'react-hook-form'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader'; import { WebhookFormMode } from '@/settings/developers/constants/WebhookFormMode'; import { useWebhookForm } from '@/settings/developers/hooks/useWebhookForm'; import { SettingsPath } from '@/types/SettingsPath'; import { Select } from '@/ui/input/components/Select'; import { TextArea } from '@/ui/input/components/TextArea'; import { TextInput } from '@/ui/input/components/TextInput'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import styled from '@emotion/styled'; import { Trans, useLingui } from '@lingui/react/macro'; import { getUrlHostnameOrThrow, isDefined, isValidUrl, } from 'twenty-shared/utils'; import { H2Title, IconBox, IconNorthStar, IconPlus, IconTrash, useIcons, } from 'twenty-ui/display'; import { Button, IconButton, SelectOption } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; const OBJECT_DROPDOWN_WIDTH = 340; const ACTION_DROPDOWN_WIDTH = 140; const OBJECT_MOBILE_WIDTH = 150; const ACTION_MOBILE_WIDTH = 140; const StyledFilterRow = styled.div<{ isMobile: boolean }>` display: grid; grid-template-columns: ${({ isMobile }) => isMobile ? `${OBJECT_MOBILE_WIDTH}px ${ACTION_MOBILE_WIDTH}px auto` : `${OBJECT_DROPDOWN_WIDTH}px ${ACTION_DROPDOWN_WIDTH}px auto`}; gap: ${({ theme }) => theme.spacing(2)}; margin-bottom: ${({ theme }) => theme.spacing(2)}; align-items: center; `; const StyledPlaceholder = styled.div` height: ${({ theme }) => theme.spacing(8)}; width: ${({ theme }) => theme.spacing(8)}; `; const DELETE_WEBHOOK_MODAL_ID = 'delete-webhook-modal'; type SettingsDevelopersWebhookFormProps = { webhookId?: string; mode: WebhookFormMode; }; export const SettingsDevelopersWebhookForm = ({ webhookId, mode, }: SettingsDevelopersWebhookFormProps) => { const { t } = useLingui(); const navigate = useNavigateSettings(); const { objectMetadataItems } = useObjectMetadataItems(); const isMobile = useIsMobile(); const { getIcon } = useIcons(); const { openModal } = useModal(); const { formConfig, loading, canSave, handleSave, updateOperation, removeOperation, deleteWebhook, isCreationMode, error, } = useWebhookForm({ webhookId, mode }); const getTitle = () => { if (isCreationMode) { return 'New Webhook'; } const targetUrl = formConfig.watch('targetUrl'); if (isDefined(targetUrl) && isValidUrl(targetUrl.trim())) { return getUrlHostnameOrThrow(targetUrl); } }; if ((loading && !isCreationMode) || isDefined(error)) { return ; } const objectOptions: SelectOption[] = [ { label: 'All Objects', value: '*', Icon: IconNorthStar }, ...objectMetadataItems.map((item) => ({ label: item.labelPlural, value: item.nameSingular, Icon: getIcon(item.icon), })), ]; const actionOptions: SelectOption[] = [ { label: 'All', value: '*', Icon: IconNorthStar }, { label: 'Created', value: 'created', Icon: IconPlus }, { label: 'Updated', value: 'updated', Icon: IconBox }, { label: 'Deleted', value: 'deleted', Icon: IconTrash }, ]; const descriptionTextAreaId = `${webhookId}-description`; const targetUrlTextInputId = `${webhookId}-target-url`; const secretTextInputId = `${webhookId}-secret`; return ( // eslint-disable-next-line react/jsx-props-no-spreading navigate(SettingsPath.Webhooks)} onSave={formConfig.handleSubmit(handleSave)} /> } >
{ return ( ); }} />
(