diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx index 36a847dda..801fd04c5 100644 --- a/packages/twenty-front/src/App.tsx +++ b/packages/twenty-front/src/App.tsx @@ -30,9 +30,11 @@ import { SettingsObjectFieldEdit } from '~/pages/settings/data-model/SettingsObj import { SettingsObjectNewFieldStep1 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1'; import { SettingsObjectNewFieldStep2 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2'; import { SettingsObjects } from '~/pages/settings/data-model/SettingsObjects'; +import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail'; +import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew'; import { SettingsDevelopers } from '~/pages/settings/developers/SettingsDevelopers'; -import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/SettingsDevelopersApiKeyDetail'; -import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/SettingsDevelopersApiKeysNew'; +import { SettingsDevelopersWebhooksDetail } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail'; +import { SettingsDevelopersWebhooksNew } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew'; import { SettingsAppearance } from '~/pages/settings/SettingsAppearance'; import { SettingsProfile } from '~/pages/settings/SettingsProfile'; import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace'; @@ -140,6 +142,14 @@ export const App = () => { path={SettingsPath.DevelopersApiKeyDetail} element={} /> + } + /> + } + /> } /> diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysFieldItemTableRow.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysFieldItemTableRow.tsx index b0c6378d1..f2292d94b 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysFieldItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsApiKeysFieldItemTableRow.tsx @@ -1,7 +1,7 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { ApiFieldItem } from '@/settings/developers/types/ApiFieldItem'; +import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem'; import { IconChevronRight } from '@/ui/display/icon'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; diff --git a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx index 95c21f1e6..fc391fd27 100644 --- a/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/developers/components/SettingsDevelopersWebhookTableRow.tsx @@ -2,9 +2,8 @@ import React from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { WebhookFieldItem } from '@/settings/developers/types/WebhookFieldItem'; +import { WebhookFieldItem } from '@/settings/developers/types/webhook/WebhookFieldItem'; import { IconChevronRight } from '@/ui/display/icon'; -import { SoonPill } from '@/ui/display/pill/components/SoonPill'; import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableRow } from '@/ui/layout/table/components/TableRow'; @@ -36,18 +35,14 @@ export const SettingsDevelopersWebhookTableRow = ({ }) => { const theme = useTheme(); - const soon = true; // Temporarily disabled while awaiting the development of the feature. - const onClickAction = !soon ? () => onClick() : undefined; - return ( - + {fieldItem.targetUrl} - {soon && } ); diff --git a/packages/twenty-front/src/modules/settings/developers/types/ApiFieldItem.ts b/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiFieldItem.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/developers/types/ApiFieldItem.ts rename to packages/twenty-front/src/modules/settings/developers/types/api-key/ApiFieldItem.ts diff --git a/packages/twenty-front/src/modules/settings/developers/types/ApiKey.ts b/packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/developers/types/ApiKey.ts rename to packages/twenty-front/src/modules/settings/developers/types/api-key/ApiKey.ts diff --git a/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts b/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts new file mode 100644 index 000000000..77f44b359 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/developers/types/webhook/Webhook.ts @@ -0,0 +1,5 @@ +export type Webhook = { + id: string; + targetUrl: string; + operation: string; +}; diff --git a/packages/twenty-front/src/modules/settings/developers/types/WebhookFieldItem.ts b/packages/twenty-front/src/modules/settings/developers/types/webhook/WebhookFieldItem.ts similarity index 100% rename from packages/twenty-front/src/modules/settings/developers/types/WebhookFieldItem.ts rename to packages/twenty-front/src/modules/settings/developers/types/webhook/WebhookFieldItem.ts diff --git a/packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts b/packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts index 80ff7427a..a98044815 100644 --- a/packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts +++ b/packages/twenty-front/src/modules/settings/developers/utils/format-expiration.ts @@ -1,5 +1,5 @@ -import { ApiFieldItem } from '@/settings/developers/types/ApiFieldItem'; -import { ApiKey } from '@/settings/developers/types/ApiKey'; +import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem'; +import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; import { beautifyDateDiff } from '~/utils/date-utils'; export const formatExpiration = ( diff --git a/packages/twenty-front/src/modules/types/SettingsPath.ts b/packages/twenty-front/src/modules/types/SettingsPath.ts index a73126399..f2ffab8ab 100644 --- a/packages/twenty-front/src/modules/types/SettingsPath.ts +++ b/packages/twenty-front/src/modules/types/SettingsPath.ts @@ -17,4 +17,6 @@ export enum SettingsPath { Developers = '', DevelopersNewApiKey = 'api-keys/new', DevelopersApiKeyDetail = 'api-keys/:apiKeyId', + DevelopersNewWebhook = 'webhooks/new', + DevelopersNewWebhookDetail = 'webhooks/:webhookId', } diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx b/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx index 0e304cb7b..f0bf687a3 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx +++ b/packages/twenty-front/src/pages/settings/developers/SettingsDevelopers.tsx @@ -2,8 +2,8 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { IconSettings } from '@/ui/display/icon'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; -import { SettingsDevelopersApiKeys } from '~/pages/settings/developers/SettingsDevelopersApiKeys'; -import { SettingsDevelopersWebhooks } from '~/pages/settings/developers/SettingsDevelopersWebhooks'; +import { SettingsDevelopersApiKeys } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeys'; +import { SettingsDevelopersWebhooks } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooks'; export const SettingsDevelopers = () => { return ( diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeys.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeys.stories.tsx index bad6956b1..46dd7c17a 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeys.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeys.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { SettingsDevelopersApiKeys } from '~/pages/settings/developers/SettingsDevelopersApiKeys'; +import { SettingsDevelopersApiKeys } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeys'; import { PageDecorator, PageDecoratorArgs, diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysDetail.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysDetail.stories.tsx index 60175a3b5..f4470b344 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysDetail.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysDetail.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/SettingsDevelopersApiKeyDetail'; +import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail'; import { PageDecorator, PageDecoratorArgs, diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysNew.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysNew.stories.tsx index fcc0e6f0a..11846c79a 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysNew.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersApiKeysNew.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/SettingsDevelopersApiKeysNew'; +import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew'; import { PageDecorator, PageDecoratorArgs, diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersWebhooks.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersWebhooks.stories.tsx index 8ea6c81d8..6c074afd7 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersWebhooks.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/SettingsDevelopersWebhooks.stories.tsx @@ -1,6 +1,6 @@ import { Meta, StoryObj } from '@storybook/react'; -import { SettingsDevelopersWebhooks } from '~/pages/settings/developers/SettingsDevelopersWebhooks'; +import { SettingsDevelopersWebhooks } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooks'; import { PageDecorator, PageDecoratorArgs, diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx similarity index 96% rename from packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeyDetail.tsx rename to packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index bde08614e..b8a07b857 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -13,7 +13,7 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { ApiKeyInput } from '@/settings/developers/components/ApiKeyInput'; import { useGeneratedApiKeys } from '@/settings/developers/hooks/useGeneratedApiKeys'; import { generatedApiKeyFamilyState } from '@/settings/developers/states/generatedApiKeyFamilyState'; -import { ApiKey } from '@/settings/developers/types/ApiKey'; +import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; import { computeNewExpirationDate } from '@/settings/developers/utils/compute-new-expiration-date'; import { formatExpiration } from '@/settings/developers/utils/format-expiration'; import { IconRepeat, IconSettings, IconTrash } from '@/ui/display/icon'; @@ -127,8 +127,8 @@ export const SettingsDevelopersApiKeyDetail = () => { diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeys.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx similarity index 94% rename from packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeys.tsx rename to packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx index a9c74c195..5348d01f5 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeys.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeys.tsx @@ -4,8 +4,8 @@ import styled from '@emotion/styled'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SettingsApiKeysFieldItemTableRow } from '@/settings/developers/components/SettingsApiKeysFieldItemTableRow'; -import { ApiFieldItem } from '@/settings/developers/types/ApiFieldItem'; -import { ApiKey } from '@/settings/developers/types/ApiKey'; +import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem'; +import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; import { formatExpirations } from '@/settings/developers/utils/format-expiration'; import { IconPlus } from '@/ui/display/icon'; import { H2Title } from '@/ui/display/typography/components/H2Title'; diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeysNew.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx similarity index 93% rename from packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeysNew.tsx rename to packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index b672ebab2..c13f6931c 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersApiKeysNew.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -9,7 +9,7 @@ import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderCon import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { ExpirationDates } from '@/settings/developers/constants/expirationDates'; import { useGeneratedApiKeys } from '@/settings/developers/hooks/useGeneratedApiKeys'; -import { ApiKey } from '@/settings/developers/types/ApiKey'; +import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; import { IconSettings } from '@/ui/display/icon'; import { H2Title } from '@/ui/display/typography/components/H2Title'; import { Select } from '@/ui/input/components/Select'; @@ -35,7 +35,7 @@ export const SettingsDevelopersApiKeysNew = () => { objectNameSingular: CoreObjectNameSingular.ApiKey, }); - const onSave = async () => { + const handleSave = async () => { const expiresAt = DateTime.now() .plus({ days: formValues.expirationDate ?? 30 }) .toString(); @@ -66,8 +66,8 @@ export const SettingsDevelopersApiKeysNew = () => { { onCancel={() => { navigate('/settings/developers'); }} - onSave={onSave} + onSave={handleSave} />
diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx new file mode 100644 index 000000000..3434ed285 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail.tsx @@ -0,0 +1,73 @@ +import { useNavigate, useParams } from 'react-router-dom'; + +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; +import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord'; +import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; +import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { IconSettings, IconTrash } from '@/ui/display/icon'; +import { H2Title } from '@/ui/display/typography/components/H2Title'; +import { Button } from '@/ui/input/button/components/Button'; +import { TextInput } from '@/ui/input/components/TextInput'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { Section } from '@/ui/layout/section/components/Section'; +import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; + +export const SettingsDevelopersWebhooksDetail = () => { + const navigate = useNavigate(); + const { webhookId = '' } = useParams(); + const { record: webhookData } = useFindOneRecord({ + objectNameSingular: CoreObjectNameSingular.Webhook, + objectRecordId: webhookId, + }); + const { deleteOneRecord: deleteOneWebhook } = useDeleteOneRecord({ + objectNameSingular: CoreObjectNameSingular.Webhook, + }); + const deleteWebhook = () => { + deleteOneWebhook(webhookId); + navigate('/settings/developers'); + }; + return ( + <> + {webhookData?.targetUrl && ( + + + + + +
+ + +
+
+ +
+
+
+ )} + + ); +}; diff --git a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersWebhooks.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooks.tsx similarity index 96% rename from packages/twenty-front/src/pages/settings/developers/SettingsDevelopersWebhooks.tsx rename to packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooks.tsx index 31a59129b..2033bf551 100644 --- a/packages/twenty-front/src/pages/settings/developers/SettingsDevelopersWebhooks.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooks.tsx @@ -4,7 +4,7 @@ import styled from '@emotion/styled'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SettingsDevelopersWebhookTableRow } from '@/settings/developers/components/SettingsDevelopersWebhookTableRow'; -import { WebhookFieldItem } from '@/settings/developers/types/WebhookFieldItem'; +import { WebhookFieldItem } from '@/settings/developers/types/webhook/WebhookFieldItem'; import { IconPlus } from '@/ui/display/icon'; import { H2Title } from '@/ui/display/typography/components/H2Title'; import { Button } from '@/ui/input/button/components/Button'; @@ -66,7 +66,6 @@ export const SettingsDevelopersWebhooks = () => { title="Create Webhook" size="small" variant="secondary" - soon={true} onClick={() => { navigate('/settings/developers/webhooks/new'); }} diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew.tsx new file mode 100644 index 000000000..4de247f31 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew.tsx @@ -0,0 +1,75 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; + +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; +import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; +import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer'; +import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { Webhook } from '@/settings/developers/types/webhook/Webhook'; +import { IconSettings } from '@/ui/display/icon'; +import { H2Title } from '@/ui/display/typography/components/H2Title'; +import { TextInput } from '@/ui/input/components/TextInput'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { Section } from '@/ui/layout/section/components/Section'; +import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; + +export const SettingsDevelopersWebhooksNew = () => { + const navigate = useNavigate(); + const [formValues, setFormValues] = useState<{ + targetUrl: string; + operation: string; + }>({ + targetUrl: '', + operation: '*.*', + }); + const { createOneRecord: createOneWebhook } = useCreateOneRecord({ + objectNameSingular: CoreObjectNameSingular.Webhook, + }); + const handleSave = async () => { + const newWebhook = await createOneWebhook?.(formValues); + if (!newWebhook) { + return; + } + navigate(`/settings/developers/webhooks/${newWebhook.id}`); + }; + const canSave = !!formValues.targetUrl && createOneWebhook; + return ( + + + + + { + navigate('/settings/developers'); + }} + onSave={handleSave} + /> + +
+ + { + setFormValues((prevState) => ({ + ...prevState, + targetUrl: value, + })); + }} + fullWidth + /> +
+
+
+ ); +}; diff --git a/packages/twenty-front/src/testing/mock-data/api-keys.ts b/packages/twenty-front/src/testing/mock-data/api-keys.ts index ca17413d5..c9160aa0e 100644 --- a/packages/twenty-front/src/testing/mock-data/api-keys.ts +++ b/packages/twenty-front/src/testing/mock-data/api-keys.ts @@ -1,4 +1,4 @@ -import { ApiKey } from '@/settings/developers/types/ApiKey'; +import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; type MockedApiKey = Pick< ApiKey,