Webhook follow up (#10124)

- fix webhook creation
- fix pointer
This commit is contained in:
martmull
2025-02-11 17:30:11 +01:00
committed by GitHub
parent 5252b22b64
commit 83bf2d1739
13 changed files with 184 additions and 113 deletions

View File

@ -5,6 +5,7 @@ import { IconChevronRight } from 'twenty-ui';
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { getUrlHostname } from '~/utils/url/getUrlHostname';
export const StyledApisFieldTableRow = styled(TableRow)`
grid-template-columns: 1fr 28px;
@ -37,7 +38,9 @@ export const SettingsDevelopersWebhookTableRow = ({
return (
<StyledApisFieldTableRow to={to}>
<StyledUrlTableCell>{fieldItem.targetUrl}</StyledUrlTableCell>
<StyledUrlTableCell>
{getUrlHostname(fieldItem.targetUrl, { keepPath: true })}
</StyledUrlTableCell>
<StyledIconTableCell>
<StyledIconChevronRight
size={theme.icon.size.md}

View File

@ -2,6 +2,7 @@ import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useState } from 'react';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
import { Webhook } from '@/settings/developers/types/webhook/Webhook';
import { useDebouncedCallback } from 'use-debounce';
import { WebhookOperationType } from '~/pages/settings/developers/webhooks/types/WebhookOperationsType';
@ -11,6 +12,7 @@ import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { SettingsPath } from '@/types/SettingsPath';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { isValidUrl } from '~/utils/url/isValidUrl';
import { getUrlHostname } from '~/utils/url/getUrlHostname';
type WebhookFormData = {
targetUrl: string;
@ -19,10 +21,18 @@ type WebhookFormData = {
secret?: string;
};
export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
export const useWebhookUpdateForm = ({
webhookId,
isCreationMode,
}: {
webhookId: string;
isCreationMode: boolean;
}) => {
const navigate = useNavigateSettings();
const [loading, setLoading] = useState(true);
const [isCreated, setIsCreated] = useState(!isCreationMode);
const [loading, setLoading] = useState(!isCreationMode);
const [title, setTitle] = useState(isCreationMode ? 'New Webhook' : '');
const [formData, setFormData] = useState<WebhookFormData>({
targetUrl: '',
@ -37,6 +47,10 @@ export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
objectNameSingular: CoreObjectNameSingular.Webhook,
});
const { createOneRecord } = useCreateOneRecord<Webhook>({
objectNameSingular: CoreObjectNameSingular.Webhook,
});
const addEmptyOperationIfNecessary = (
newOperations: WebhookOperationType[],
) => {
@ -49,34 +63,6 @@ export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
return newOperations;
};
useFindOneRecord({
objectNameSingular: CoreObjectNameSingular.Webhook,
objectRecordId: webhookId,
onCompleted: (data) => {
const baseOperations = data?.operations
? data.operations.map((op: string) => {
const [object, action] = op.split('.');
return { object, action };
})
: data?.operation
? [
{
object: data.operation.split('.')[0],
action: data.operation.split('.')[1],
},
]
: [];
const operations = addEmptyOperationIfNecessary(baseOperations);
setFormData({
targetUrl: data.targetUrl,
description: data.description,
operations,
secret: data.secret,
});
setLoading(false);
},
});
const cleanAndFormatOperations = (operations: WebhookOperationType[]) => {
return Array.from(
new Set(
@ -90,6 +76,19 @@ export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
const handleSave = useDebouncedCallback(async () => {
const cleanedOperations = cleanAndFormatOperations(formData.operations);
const webhookData = {
...(isTargetUrlValid && { targetUrl: formData.targetUrl.trim() }),
operations: cleanedOperations,
description: formData.description,
secret: formData.secret,
};
if (!isCreated) {
await createOneRecord({ id: webhookId, ...webhookData });
setIsCreated(true);
return;
}
await updateOneRecord({
idToUpdate: webhookId,
updateOneRecordInput: {
@ -104,7 +103,13 @@ export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
const validateData = (data: Partial<WebhookFormData>) => {
if (isDefined(data?.targetUrl)) {
const trimmedUrl = data.targetUrl.trim();
setIsTargetUrlValid(isValidUrl(trimmedUrl));
const isTargetUrlValid = isValidUrl(trimmedUrl);
setIsTargetUrlValid(isTargetUrlValid);
if (isTargetUrlValid) {
setTitle(
getUrlHostname(trimmedUrl, { keepPath: true }) || 'New Webhook',
);
}
}
};
@ -147,8 +152,41 @@ export const useWebhookUpdateForm = ({ webhookId }: { webhookId: string }) => {
navigate(SettingsPath.Developers);
};
useFindOneRecord({
skip: isCreationMode,
objectNameSingular: CoreObjectNameSingular.Webhook,
objectRecordId: webhookId,
onCompleted: (data) => {
const baseOperations = data?.operations
? data.operations.map((op: string) => {
const [object, action] = op.split('.');
return { object, action };
})
: data?.operation
? [
{
object: data.operation.split('.')[0],
action: data.operation.split('.')[1],
},
]
: [];
const operations = addEmptyOperationIfNecessary(baseOperations);
setFormData({
targetUrl: data.targetUrl,
description: data.description,
operations,
secret: data.secret,
});
setTitle(
getUrlHostname(data.targetUrl, { keepPath: true }) || 'New Webhook',
);
setLoading(false);
},
});
return {
formData,
title,
isTargetUrlValid,
updateWebhook,
updateOperation,