@ -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}
|
||||
|
||||
@ -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,
|
||||
|
||||
Reference in New Issue
Block a user