Add description for Developers/webhook page (#6327)

- Add optional description field to webhook page in developer settings.

Fix https://github.com/twentyhq/twenty/issues/6236

---------

Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
This commit is contained in:
AbdulQader Qassab 2024-07-31 12:59:30 +04:00 committed by GitHub
parent ee4f1da956
commit 50f1cd352d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 83 additions and 6 deletions

View File

@ -1,6 +1,7 @@
export type Webhook = {
id: string;
targetUrl: string;
description?: string;
operation: string;
__typename: 'Webhook';
};

View File

@ -27,6 +27,7 @@ const meta: Meta<PageDecoratorArgs> = {
id: '1',
createdAt: '2021-08-27T12:00:00Z',
targetUrl: 'https://example.com/webhook',
description: 'A Sample Description',
updatedAt: '2021-08-27T12:00:00Z',
operation: 'create',
__typename: 'Webhook',

View File

@ -1,24 +1,34 @@
import { useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { H2Title, IconSettings, IconTrash } from 'twenty-ui';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
import { Section } from '@/ui/layout/section/components/Section';
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { useState } from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import { H2Title, IconSettings, IconTrash } from 'twenty-ui';
type SettingsDevelopersWebhooksDetailForm = {
description?: string;
};
export const SettingsDevelopersWebhooksDetail = () => {
const [isDeleteWebhookModalOpen, setIsDeleteWebhookModalOpen] =
useState(false);
const navigate = useNavigate();
const { webhookId = '' } = useParams();
const { enqueueSnackBar } = useSnackBar();
const { record: webhookData } = useFindOneRecord({
objectNameSingular: CoreObjectNameSingular.Webhook,
objectRecordId: webhookId,
@ -26,12 +36,37 @@ export const SettingsDevelopersWebhooksDetail = () => {
const { deleteOneRecord: deleteOneWebhook } = useDeleteOneRecord({
objectNameSingular: CoreObjectNameSingular.Webhook,
});
const { updateOneRecord } = useUpdateOneRecord({
objectNameSingular: CoreObjectNameSingular.Webhook,
});
const deleteWebhook = () => {
deleteOneWebhook(webhookId);
navigate('/settings/developers');
};
const formConfig = useForm<SettingsDevelopersWebhooksDetailForm>();
const { isDirty, isValid, isSubmitting } = formConfig.formState;
const canSave = isDirty && isValid && !isSubmitting;
const handleSave = async (
formValues: SettingsDevelopersWebhooksDetailForm,
) => {
try {
await updateOneRecord({
idToUpdate: webhookId,
updateOneRecordInput: formValues,
});
navigate('/settings/developers');
} catch (error) {
enqueueSnackBar((error as Error).message, {
variant: SnackBarVariant.Error,
});
}
};
return (
<>
// eslint-disable-next-line react/jsx-props-no-spreading
<FormProvider {...formConfig}>
{webhookData?.targetUrl && (
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
<SettingsPageContainer>
@ -42,6 +77,11 @@ export const SettingsDevelopersWebhooksDetail = () => {
{ children: 'Webhook' },
]}
/>
<SaveAndCancelButtons
onCancel={() => navigate(`/settings/developers`)}
onSave={formConfig.handleSubmit(handleSave)}
isSaveDisabled={!canSave}
/>
</SettingsHeaderContainer>
<Section>
<H2Title
@ -55,6 +95,25 @@ export const SettingsDevelopersWebhooksDetail = () => {
fullWidth
/>
</Section>
<Section>
<H2Title
title="Description"
description="An optional description"
/>
<Controller
name="description"
control={formConfig.control}
defaultValue={webhookData?.description ?? null}
render={({ field: { onChange, value } }) => (
<TextArea
placeholder="Write a description"
minRows={4}
value={value ?? undefined}
onChange={(nextValue) => onChange(nextValue ?? null)}
/>
)}
/>
</Section>
<Section>
<H2Title
title="Danger zone"
@ -86,6 +145,6 @@ export const SettingsDevelopersWebhooksDetail = () => {
</SettingsPageContainer>
</SubMenuTopBarContainer>
)}
</>
</FormProvider>
);
};

View File

@ -22,6 +22,10 @@ export const computeWebhooks = (
type: 'string',
example: 'https://example.com/incomingWebhook',
},
description: {
type: 'string',
example: 'A sample description',
},
eventType: {
type: 'string',
enum: [

View File

@ -325,6 +325,7 @@ export const VIEW_STANDARD_FIELD_IDS = {
export const WEBHOOK_STANDARD_FIELD_IDS = {
targetUrl: '20202020-1229-45a8-8cf4-85c9172aae12',
operation: '20202020-15b7-458e-bf30-74770a54410c',
description: '20202020-15b7-458e-bf30-74770a54410d',
};
export const WORKFLOW_EVENT_LISTENER_STANDARD_FIELD_IDS = {

View File

@ -3,6 +3,7 @@ import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WEBHOOK_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
@ -36,4 +37,14 @@ export class WebhookWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconCheckbox',
})
operation: string;
@WorkspaceField({
standardId: WEBHOOK_STANDARD_FIELD_IDS.description,
type: FieldMetadataType.TEXT,
label: 'Description',
description: undefined,
icon: 'IconInfo',
})
@WorkspaceIsNullable()
description: string;
}