From e44d525e839487312c41da449ff49a704fabca63 Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Thu, 24 Oct 2024 17:27:56 +0200 Subject: [PATCH 01/50] Prevent workflow right drawer flickering when selecting an action type (#8028) In this PR: - Use a stable id for create-step nodes; it makes it possible to preserve their selected attribute and keep them open even after the flow is re-generated - Preemptively open the WorkflowStepEdit right drawer for the created action https://github.com/user-attachments/assets/c19e6820-e198-4d06-98ae-898bd6e53e33 Fixes https://github.com/twentyhq/private-issues/issues/123 --- .../workflow/components/WorkflowDiagramEffect.tsx | 10 ++++------ .../src/modules/workflow/hooks/useCreateStep.ts | 9 +++++++++ .../src/modules/workflow/utils/addCreateStepNodes.ts | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramEffect.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramEffect.tsx index 8b714cc76..a95b709e1 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramEffect.tsx @@ -27,7 +27,9 @@ export const WorkflowDiagramEffect = ({ workflowDiagramState, ); - const nextWorkflowDiagram = getWorkflowVersionDiagram(currentVersion); + const nextWorkflowDiagram = addCreateStepNodes( + getWorkflowVersionDiagram(currentVersion), + ); let mergedWorkflowDiagram = nextWorkflowDiagram; if (isDefined(previousWorkflowDiagram)) { @@ -37,11 +39,7 @@ export const WorkflowDiagramEffect = ({ ); } - const workflowDiagramWithCreateStepNodes = addCreateStepNodes( - mergedWorkflowDiagram, - ); - - set(workflowDiagramState, workflowDiagramWithCreateStepNodes); + set(workflowDiagramState, mergedWorkflowDiagram); }; }, [], diff --git a/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts b/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts index e439edc2d..a9327a6e8 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useCreateStep.ts @@ -1,8 +1,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; +import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; +import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion'; import { workflowCreateStepFromParentStepIdState } from '@/workflow/states/workflowCreateStepFromParentStepIdState'; import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/states/workflowDiagramTriggerNodeSelectionState'; +import { workflowSelectedNodeState } from '@/workflow/states/workflowSelectedNodeState'; import { WorkflowStep, WorkflowStepType, @@ -19,6 +22,9 @@ export const useCreateStep = ({ }: { workflow: WorkflowWithCurrentVersion; }) => { + const { openRightDrawer } = useRightDrawer(); + const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState); + const workflowCreateStepFromParentStepId = useRecoilValue( workflowCreateStepFromParentStepIdState, ); @@ -84,6 +90,9 @@ export const useCreateStep = ({ nodeToAdd: newStep, }); + setWorkflowSelectedNode(newStep.id); + openRightDrawer(RightDrawerPages.WorkflowStepEdit); + /** * After the step has been created, select it. * As the `insertNodeAndSave` function mutates the cached workflow before resolving, diff --git a/packages/twenty-front/src/modules/workflow/utils/addCreateStepNodes.ts b/packages/twenty-front/src/modules/workflow/utils/addCreateStepNodes.ts index 381d05889..ffde2d1d8 100644 --- a/packages/twenty-front/src/modules/workflow/utils/addCreateStepNodes.ts +++ b/packages/twenty-front/src/modules/workflow/utils/addCreateStepNodes.ts @@ -16,7 +16,9 @@ export const addCreateStepNodes = ({ nodes, edges }: WorkflowDiagram) => { for (const node of nodesWithoutTargets) { const newCreateStepNode: WorkflowDiagramNode = { - id: v4(), + // FIXME: We need a stable id for create step nodes to be able to preserve their selected status. + // FIXME: In the future, we'll have conditions and loops. We'll have to set an id to each branch so we can have this stable id. + id: 'branch-1__create-step', type: 'create-step', data: { nodeType: 'create-step', From b09ecfbb8ca0ccdb0d9b1bc9567b1f158c3d6021 Mon Sep 17 00:00:00 2001 From: "gitstart-app[bot]" <57568882+gitstart-app[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:50:14 +0200 Subject: [PATCH 02/50] Migrate to twenty-ui - display (#8004) This PR was created by [GitStart](https://gitstart.com/) to address the requirements from this ticket: [TWNTY-6871](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-6871). --- ### Description Migrate: - Info display component - Status display component - SeparatorLineText display component ### Demo ###### SeparatorLineText In Storybook ![](https://assets-service.gitstart.com/4814/c0a2cd49-e545-469a-b3d3-c02eb462b60d.png) Info Component on Storybook ![](https://assets-service.gitstart.com/4814/6f3019c5-99e0-4365-a81e-241294887f9e.png) Status Component on Storybook ![](https://assets-service.gitstart.com/4814/29b5142a-468f-4d7e-88ff-4f3bfdd5abda.png) ###### Fixes twentyhq/private-issues#95 --------- Co-authored-by: gitstart-twenty Co-authored-by: Charles Bochet --- .../src/__stories__/AppRouter.stories.tsx | 6 ++-- ...sePageChangeEffectNavigateLocation.test.ts | 1 + .../src/hooks/useCleanRecoilState.ts | 7 ++-- .../modules/apollo/hooks/useApolloFactory.ts | 2 +- .../effect-components/PageChangeEffect.tsx | 2 +- .../auth/sign-in-up/hooks/useSignInUp.tsx | 10 +++--- .../hooks/useWorkspaceFromInviteHash.ts | 3 +- .../AppNavigationDrawer.stories.tsx | 3 +- .../utils/__tests__/indexAppPath.test.ts | 1 - ...untsConnectedAccountsRowRightContainer.tsx | 2 +- .../hooks/useTriggerGoogleApisOAuth.ts | 2 +- .../SettingsIntegrationComponent.tsx | 13 ++++++-- ...ntegrationDatabaseConnectionSyncStatus.tsx | 2 +- ...tegrationEditDatabaseConnectionContent.tsx | 3 +- .../hooks/useDatabaseConnection.ts | 2 +- ...gsSSOIdentityProviderRowRightContainer.tsx | 2 +- .../hooks/useWorkspaceSwitching.ts | 14 ++++---- .../twenty-front/src/pages/auth/Authorize.tsx | 1 + .../pages/auth/__stories__/Invite.stories.tsx | 2 +- .../auth/__stories__/SignInUp.stories.tsx | 4 +-- .../pages/impersonate/ImpersonateEffect.tsx | 2 +- .../__stories__/ImpersonateEffect.stories.tsx | 2 +- .../src/pages/not-found/NotFound.tsx | 1 + .../src/pages/onboarding/InviteTeam.tsx | 3 +- .../src/pages/onboarding/PaymentSuccess.tsx | 9 ++--- .../src/pages/onboarding/SyncEmails.tsx | 19 ++++++----- .../__stories__/CreateProfile.stories.tsx | 2 +- .../__stories__/CreateWorkspace.stories.tsx | 2 +- .../__stories__/InviteTeam.stories.tsx | 4 +-- .../__stories__/PaymentSuccess.stories.tsx | 2 +- .../__stories__/SyncEmails.stories.tsx | 4 +-- .../src/pages/settings/SettingsBilling.tsx | 2 +- .../settings/SettingsWorkspaceMembers.tsx | 33 ++++++++++--------- .../data-model/SettingsObjectEdit.tsx | 19 ++++++----- .../data-model/SettingsObjectFieldEdit.tsx | 19 ++++++----- ...ttingsIntegrationNewDatabaseConnection.tsx | 2 +- packages/twenty-front/tsup.ui.index.tsx | 1 - packages/twenty-ui/src/display/index.ts | 3 ++ .../src}/display/info/components/Info.tsx | 8 ++--- .../components/__stories__/Info.stories.tsx | 8 +++-- .../src}/display/status/components/Status.tsx | 5 ++- .../components/__stories__/Status.stories.tsx | 5 ++- .../text/components/SeparatorLineText.tsx | 0 .../__stories__/SeparatorLineText.stories.tsx | 2 +- .../src/input/button/components/Button.tsx | 4 +-- 45 files changed, 133 insertions(+), 110 deletions(-) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/info/components/Info.tsx (93%) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/info/components/__stories__/Info.stories.tsx (84%) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/status/components/Status.tsx (91%) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/status/components/__stories__/Status.stories.tsx (94%) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/text/components/SeparatorLineText.tsx (100%) rename packages/{twenty-front/src/modules/ui => twenty-ui/src}/display/text/components/__stories__/SeparatorLineText.stories.tsx (89%) diff --git a/packages/twenty-front/src/__stories__/AppRouter.stories.tsx b/packages/twenty-front/src/__stories__/AppRouter.stories.tsx index 9d2fe91a6..f322919ba 100644 --- a/packages/twenty-front/src/__stories__/AppRouter.stories.tsx +++ b/packages/twenty-front/src/__stories__/AppRouter.stories.tsx @@ -1,18 +1,18 @@ import { getOperationName } from '@apollo/client/utilities'; import { jest } from '@storybook/jest'; import { Meta, StoryObj } from '@storybook/react'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { HelmetProvider } from 'react-helmet-async'; import { RecoilRoot } from 'recoil'; -import { IconsProvider } from 'twenty-ui'; import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; import indexAppPath from '@/navigation/utils/indexAppPath'; -import { AppPath } from '@/types/AppPath'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { AppRouter } from '@/app/components/AppRouter'; +import { AppPath } from '@/types/AppPath'; +import { IconsProvider } from 'twenty-ui'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { mockedUserData } from '~/testing/mock-data/users'; diff --git a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts index 95c2a58b7..a7b683e66 100644 --- a/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts +++ b/packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts @@ -2,6 +2,7 @@ import { useIsLogged } from '@/auth/hooks/useIsLogged'; import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath'; import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; import { AppPath } from '@/types/AppPath'; + import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus'; import { OnboardingStatus, SubscriptionStatus } from '~/generated/graphql'; diff --git a/packages/twenty-front/src/hooks/useCleanRecoilState.ts b/packages/twenty-front/src/hooks/useCleanRecoilState.ts index 3f0a41df4..9da98c006 100644 --- a/packages/twenty-front/src/hooks/useCleanRecoilState.ts +++ b/packages/twenty-front/src/hooks/useCleanRecoilState.ts @@ -1,8 +1,9 @@ -import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; -import { SettingsPath } from '@/types/SettingsPath'; import { apiKeyTokenState } from '@/settings/developers/states/generatedApiKeyTokenState'; -import { useRecoilValue, useResetRecoilState } from 'recoil'; import { AppPath } from '@/types/AppPath'; +import { SettingsPath } from '@/types/SettingsPath'; +import { useRecoilValue, useResetRecoilState } from 'recoil'; +import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; + import { isDefined } from '~/utils/isDefined'; export const useCleanRecoilState = () => { diff --git a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts index b70cbdd17..104364957 100644 --- a/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts +++ b/packages/twenty-front/src/modules/apollo/hooks/useApolloFactory.ts @@ -10,12 +10,12 @@ import { previousUrlState } from '@/auth/states/previousUrlState'; import { tokenPairState } from '@/auth/states/tokenPairState'; import { workspacesState } from '@/auth/states/workspaces'; import { isDebugModeState } from '@/client-config/states/isDebugModeState'; -import { AppPath } from '@/types/AppPath'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { useUpdateEffect } from '~/hooks/useUpdateEffect'; import { isDefined } from '~/utils/isDefined'; +import { AppPath } from '@/types/AppPath'; import { ApolloFactory, Options } from '../services/apollo.factory'; export const useApolloFactory = (options: Partial> = {}) => { diff --git a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx index a8b05f4c0..261a04e0e 100644 --- a/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/PageChangeEffect.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; -import { IconCheckbox } from 'twenty-ui'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { @@ -21,6 +20,7 @@ import { AppPath } from '@/types/AppPath'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { SettingsPath } from '@/types/SettingsPath'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; +import { IconCheckbox } from 'twenty-ui'; import { useCleanRecoilState } from '~/hooks/useCleanRecoilState'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffectNavigateLocation'; diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUp.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUp.tsx index a80473854..53994713c 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUp.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUp.tsx @@ -5,20 +5,20 @@ import { useParams, useSearchParams } from 'react-router-dom'; import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { useReadCaptchaToken } from '@/captcha/hooks/useReadCaptchaToken'; import { useRequestFreshCaptchaToken } from '@/captcha/hooks/useRequestFreshCaptchaToken'; -import { AppPath } from '@/types/AppPath'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { useRecoilState, useSetRecoilState } from 'recoil'; +import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { isDefined } from '~/utils/isDefined'; -import { useAuth } from '../../hooks/useAuth'; +import { useSSO } from '@/auth/sign-in-up/hooks/useSSO'; +import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO'; import { SignInUpStep, signInUpStepState, } from '@/auth/states/signInUpStepState'; -import { useSSO } from '@/auth/sign-in-up/hooks/useSSO'; -import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO'; +import { AppPath } from '@/types/AppPath'; +import { useAuth } from '../../hooks/useAuth'; export enum SignInUpMode { SignIn = 'sign-in', diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts index a51365b98..0e238c3ab 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts +++ b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useWorkspaceFromInviteHash.ts @@ -3,11 +3,12 @@ import { useNavigate, useParams } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; -import { AppPath } from '@/types/AppPath'; + import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState'; +import { AppPath } from '@/types/AppPath'; import { useGetWorkspaceFromInviteHashQuery } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx b/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx index 3bb6f1aca..b7db0bd26 100644 --- a/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx +++ b/packages/twenty-front/src/modules/navigation/components/__stories__/AppNavigationDrawer.stories.tsx @@ -4,13 +4,12 @@ import { MemoryRouter } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState'; -import { AppPath } from '@/types/AppPath'; - import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator'; import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { AppPath } from '@/types/AppPath'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { AppNavigationDrawer, diff --git a/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts b/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts index 8920f6fa7..294dd6a5f 100644 --- a/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts +++ b/packages/twenty-front/src/modules/navigation/utils/__tests__/indexAppPath.test.ts @@ -1,5 +1,4 @@ import { AppPath } from '@/types/AppPath'; - import indexAppPath from '../indexAppPath'; describe('getIndexAppPath', () => { diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer.tsx index 2091be236..37ffe2a3c 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer.tsx @@ -2,7 +2,7 @@ import { ConnectedAccount } from '@/accounts/types/ConnectedAccount'; import { SettingsAccountsRowDropdownMenu } from '@/settings/accounts/components/SettingsAccountsRowDropdownMenu'; import { SyncStatus } from '@/settings/accounts/constants/SyncStatus'; import { computeSyncStatus } from '@/settings/accounts/utils/computeSyncStatus'; -import { Status } from '@/ui/display/status/components/Status'; +import { Status } from 'twenty-ui'; import styled from '@emotion/styled'; const StyledRowRightContainer = styled.div` diff --git a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerGoogleApisOAuth.ts b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerGoogleApisOAuth.ts index 921ebdea1..d17e4242a 100644 --- a/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerGoogleApisOAuth.ts +++ b/packages/twenty-front/src/modules/settings/accounts/hooks/useTriggerGoogleApisOAuth.ts @@ -1,6 +1,6 @@ +import { AppPath } from '@/types/AppPath'; import { useCallback } from 'react'; -import { AppPath } from '@/types/AppPath'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { CalendarChannelVisibility, diff --git a/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationComponent.tsx b/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationComponent.tsx index d6e6286b4..ec2a4fcbf 100644 --- a/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationComponent.tsx +++ b/packages/twenty-front/src/modules/settings/integrations/components/SettingsIntegrationComponent.tsx @@ -1,10 +1,17 @@ import { css } from '@emotion/react'; import styled from '@emotion/styled'; -import { Link } from 'react-router-dom'; -import { Button, IconArrowUpRight, IconBolt, IconPlus, Pill } from 'twenty-ui'; +import { + Button, + IconArrowUpRight, + IconBolt, + IconPlus, + Pill, + Status, +} from 'twenty-ui'; import { SettingsIntegration } from '@/settings/integrations/types/SettingsIntegration'; -import { Status } from '@/ui/display/status/components/Status'; +import { Link } from 'react-router-dom'; + import { isDefined } from '~/utils/isDefined'; interface SettingsIntegrationComponentProps { diff --git a/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus.tsx b/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus.tsx index a0a0005a0..aa8162ce8 100644 --- a/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus.tsx +++ b/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationDatabaseConnectionSyncStatus.tsx @@ -1,5 +1,5 @@ import { useGetDatabaseConnectionTables } from '@/databases/hooks/useGetDatabaseConnectionTables'; -import { Status } from '@/ui/display/status/components/Status'; +import { Status } from 'twenty-ui'; import { RemoteTableStatus } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContent.tsx b/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContent.tsx index 1a4d1a5d3..e125c0a27 100644 --- a/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContent.tsx +++ b/packages/twenty-front/src/modules/settings/integrations/database-connection/components/SettingsIntegrationEditDatabaseConnectionContent.tsx @@ -10,7 +10,6 @@ import { import { SettingsIntegration } from '@/settings/integrations/types/SettingsIntegration'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; -import { Info } from '@/ui/display/info/components/Info'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -18,7 +17,7 @@ import { Section } from '@react-email/components'; import pick from 'lodash.pick'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { Breadcrumb, H2Title } from 'twenty-ui'; +import { Breadcrumb, H2Title, Info } from 'twenty-ui'; import { z } from 'zod'; import { RemoteServer, diff --git a/packages/twenty-front/src/modules/settings/integrations/database-connection/hooks/useDatabaseConnection.ts b/packages/twenty-front/src/modules/settings/integrations/database-connection/hooks/useDatabaseConnection.ts index 3353c39dd..ec3c73df0 100644 --- a/packages/twenty-front/src/modules/settings/integrations/database-connection/hooks/useDatabaseConnection.ts +++ b/packages/twenty-front/src/modules/settings/integrations/database-connection/hooks/useDatabaseConnection.ts @@ -1,6 +1,6 @@ +import { WatchQueryFetchPolicy } from '@apollo/client'; import { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { WatchQueryFetchPolicy } from '@apollo/client'; import { useGetDatabaseConnection } from '@/databases/hooks/useGetDatabaseConnection'; import { useGetDatabaseConnectionTables } from '@/databases/hooks/useGetDatabaseConnectionTables'; diff --git a/packages/twenty-front/src/modules/settings/security/components/SettingsSSOIdentityProviderRowRightContainer.tsx b/packages/twenty-front/src/modules/settings/security/components/SettingsSSOIdentityProviderRowRightContainer.tsx index 64d8d1402..eab5f84d6 100644 --- a/packages/twenty-front/src/modules/settings/security/components/SettingsSSOIdentityProviderRowRightContainer.tsx +++ b/packages/twenty-front/src/modules/settings/security/components/SettingsSSOIdentityProviderRowRightContainer.tsx @@ -3,7 +3,7 @@ import { SettingsSecuritySSORowDropdownMenu } from '@/settings/security/components/SettingsSecuritySSORowDropdownMenu'; import { SSOIdentitiesProvidersState } from '@/settings/security/states/SSOIdentitiesProviders.state'; import { getColorBySSOIdentityProviderStatus } from '@/settings/security/utils/getColorBySSOIdentityProviderStatus'; -import { Status } from '@/ui/display/status/components/Status'; +import { Status } from 'twenty-ui'; import styled from '@emotion/styled'; import { UnwrapRecoilValue } from 'recoil'; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useWorkspaceSwitching.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useWorkspaceSwitching.ts index dfdd4082b..b7e7abf9f 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useWorkspaceSwitching.ts +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/hooks/useWorkspaceSwitching.ts @@ -1,18 +1,18 @@ import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useAuth } from '@/auth/hooks/useAuth'; +import { useSSO } from '@/auth/sign-in-up/hooks/useSSO'; +import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { + SignInUpStep, + signInUpStepState, +} from '@/auth/states/signInUpStepState'; import { tokenPairState } from '@/auth/states/tokenPairState'; import { AppPath } from '@/types/AppPath'; import { useGenerateJwtMutation } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { sleep } from '~/utils/sleep'; -import { useSSO } from '@/auth/sign-in-up/hooks/useSSO'; -import { - SignInUpStep, - signInUpStepState, -} from '@/auth/states/signInUpStepState'; -import { availableSSOIdentityProvidersState } from '@/auth/states/availableWorkspacesForSSO'; -import { useAuth } from '@/auth/hooks/useAuth'; export const useWorkspaceSwitching = () => { const setTokenPair = useSetRecoilState(tokenPairState); diff --git a/packages/twenty-front/src/pages/auth/Authorize.tsx b/packages/twenty-front/src/pages/auth/Authorize.tsx index 1019907d2..f2745a754 100644 --- a/packages/twenty-front/src/pages/auth/Authorize.tsx +++ b/packages/twenty-front/src/pages/auth/Authorize.tsx @@ -2,6 +2,7 @@ import { AppPath } from '@/types/AppPath'; import styled from '@emotion/styled'; import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; + import { MainButton, UndecoratedLink } from 'twenty-ui'; import { useAuthorizeAppMutation } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx b/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx index 3d35bb0b1..85665e8be 100644 --- a/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx +++ b/packages/twenty-front/src/pages/auth/__stories__/Invite.stories.tsx @@ -3,7 +3,6 @@ import { Meta, StoryObj } from '@storybook/react'; import { fireEvent, within } from '@storybook/test'; import { HttpResponse, graphql } from 'msw'; -import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { GET_WORKSPACE_FROM_INVITE_HASH } from '@/workspace/graphql/queries/getWorkspaceFromInviteHash'; import { @@ -12,6 +11,7 @@ import { } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; +import { AppPath } from '@/types/AppPath'; import { Invite } from '../Invite'; const meta: Meta = { diff --git a/packages/twenty-front/src/pages/auth/__stories__/SignInUp.stories.tsx b/packages/twenty-front/src/pages/auth/__stories__/SignInUp.stories.tsx index 3805d33ad..1ce73e337 100644 --- a/packages/twenty-front/src/pages/auth/__stories__/SignInUp.stories.tsx +++ b/packages/twenty-front/src/pages/auth/__stories__/SignInUp.stories.tsx @@ -1,9 +1,8 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { fireEvent, within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; -import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { PageDecorator, @@ -11,6 +10,7 @@ import { } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; +import { AppPath } from '@/types/AppPath'; import { SignInUp } from '../SignInUp'; const meta: Meta = { diff --git a/packages/twenty-front/src/pages/impersonate/ImpersonateEffect.tsx b/packages/twenty-front/src/pages/impersonate/ImpersonateEffect.tsx index 897ab095f..6ac9d3f6c 100644 --- a/packages/twenty-front/src/pages/impersonate/ImpersonateEffect.tsx +++ b/packages/twenty-front/src/pages/impersonate/ImpersonateEffect.tsx @@ -1,6 +1,6 @@ +import { isNonEmptyString } from '@sniptt/guards'; import { useCallback, useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; -import { isNonEmptyString } from '@sniptt/guards'; import { useRecoilState, useSetRecoilState } from 'recoil'; import { useIsLogged } from '@/auth/hooks/useIsLogged'; diff --git a/packages/twenty-front/src/pages/impersonate/__stories__/ImpersonateEffect.stories.tsx b/packages/twenty-front/src/pages/impersonate/__stories__/ImpersonateEffect.stories.tsx index 98fdde17b..b1b44773e 100644 --- a/packages/twenty-front/src/pages/impersonate/__stories__/ImpersonateEffect.stories.tsx +++ b/packages/twenty-front/src/pages/impersonate/__stories__/ImpersonateEffect.stories.tsx @@ -1,6 +1,5 @@ import { Meta, StoryObj } from '@storybook/react'; -import { AppPath } from '@/types/AppPath'; import { PageDecorator, PageDecoratorArgs, @@ -8,6 +7,7 @@ import { import { graphqlMocks } from '~/testing/graphqlMocks'; import { sleep } from '~/utils/sleep'; +import { AppPath } from '@/types/AppPath'; import { ImpersonateEffect } from '../ImpersonateEffect'; const meta: Meta = { diff --git a/packages/twenty-front/src/pages/not-found/NotFound.tsx b/packages/twenty-front/src/pages/not-found/NotFound.tsx index dee24fc8c..2d44a51e7 100644 --- a/packages/twenty-front/src/pages/not-found/NotFound.tsx +++ b/packages/twenty-front/src/pages/not-found/NotFound.tsx @@ -1,5 +1,6 @@ import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage'; import { AppPath } from '@/types/AppPath'; + import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import styled from '@emotion/styled'; import { diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index 42dac7188..c55be7111 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -4,7 +4,6 @@ import { currentUserState } from '@/auth/states/currentUserState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { PageHotkeyScope } from '@/types/PageHotkeyScope'; -import { SeparatorLineText } from '@/ui/display/text/components/SeparatorLineText'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { TextInputV2 } from '@/ui/input/components/TextInputV2'; @@ -27,8 +26,10 @@ import { IconCopy, LightButton, MainButton, + SeparatorLineText, } from 'twenty-ui'; import { z } from 'zod'; + import { OnboardingStatus } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { useCreateWorkspaceInvitation } from '../../modules/workspace-invitation/hooks/useCreateWorkspaceInvitation'; diff --git a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx index 0e2ed08f0..d4c51f4a2 100644 --- a/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx +++ b/packages/twenty-front/src/pages/onboarding/PaymentSuccess.tsx @@ -1,7 +1,3 @@ -import { SubTitle } from '@/auth/components/SubTitle'; -import { Title } from '@/auth/components/Title'; -import { currentUserState } from '@/auth/states/currentUserState'; -import { AppPath } from '@/types/AppPath'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; @@ -12,6 +8,11 @@ import { RGBA, UndecoratedLink, } from 'twenty-ui'; + +import { SubTitle } from '@/auth/components/SubTitle'; +import { Title } from '@/auth/components/Title'; +import { currentUserState } from '@/auth/states/currentUserState'; +import { AppPath } from '@/types/AppPath'; import { OnboardingStatus } from '~/generated/graphql'; const StyledCheckContainer = styled.div` diff --git a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx index 607e9fe80..4657a2aba 100644 --- a/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx +++ b/packages/twenty-front/src/pages/onboarding/SyncEmails.tsx @@ -1,12 +1,3 @@ -import { SubTitle } from '@/auth/components/SubTitle'; -import { Title } from '@/auth/components/Title'; -import { currentUserState } from '@/auth/states/currentUserState'; -import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard'; -import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; -import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth'; -import { AppPath } from '@/types/AppPath'; -import { PageHotkeyScope } from '@/types/PageHotkeyScope'; -import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useState } from 'react'; @@ -14,6 +5,16 @@ import { useRecoilValue } from 'recoil'; import { Key } from 'ts-key-enum'; import { ActionLink, IconGoogle, MainButton } from 'twenty-ui'; +import { SubTitle } from '@/auth/components/SubTitle'; +import { Title } from '@/auth/components/Title'; +import { currentUserState } from '@/auth/states/currentUserState'; +import { OnboardingSyncEmailsSettingsCard } from '@/onboarding/components/OnboardingSyncEmailsSettingsCard'; +import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; +import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth'; +import { PageHotkeyScope } from '@/types/PageHotkeyScope'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; + +import { AppPath } from '@/types/AppPath'; import { CalendarChannelVisibility, MessageChannelVisibility, diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx index 19512ebe1..40afb5284 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/CreateProfile.stories.tsx @@ -1,7 +1,7 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx index baccc13b2..1ac668210 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/CreateWorkspace.stories.tsx @@ -1,7 +1,7 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx index e174fc517..a09846e27 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/InviteTeam.stories.tsx @@ -1,10 +1,10 @@ +import { AppPath } from '@/types/AppPath'; import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { OnboardingStatus } from '~/generated/graphql'; -import { AppPath } from '~/modules/types/AppPath'; import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser'; import { InviteTeam } from '~/pages/onboarding/InviteTeam'; import { diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx index fccb1e3c6..22ed0e994 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/PaymentSuccess.stories.tsx @@ -1,7 +1,7 @@ import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/testing-library'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { AppPath } from '@/types/AppPath'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx index 8d9b4261e..213ad3fa5 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/SyncEmails.stories.tsx @@ -1,10 +1,10 @@ +import { AppPath } from '@/types/AppPath'; import { getOperationName } from '@apollo/client/utilities'; import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; -import { graphql, HttpResponse } from 'msw'; +import { HttpResponse, graphql } from 'msw'; import { OnboardingStatus } from '~/generated/graphql'; -import { AppPath } from '~/modules/types/AppPath'; import { GET_CURRENT_USER } from '~/modules/users/graphql/queries/getCurrentUser'; import { SyncEmails } from '~/pages/onboarding/SyncEmails'; import { diff --git a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx index e30f3e88d..bbb802add 100644 --- a/packages/twenty-front/src/pages/settings/SettingsBilling.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsBilling.tsx @@ -6,6 +6,7 @@ import { IconCalendarEvent, IconCircleX, IconCreditCard, + Info, } from 'twenty-ui'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; @@ -15,7 +16,6 @@ import { SettingsPageContainer } from '@/settings/components/SettingsPageContain import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { AppPath } from '@/types/AppPath'; import { SettingsPath } from '@/types/SettingsPath'; -import { Info } from '@/ui/display/info/components/Info'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx index 0986ea87e..6145485c2 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -1,3 +1,20 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { isNonEmptyArray } from '@sniptt/guards'; +import { useState } from 'react'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { + AppTooltip, + Avatar, + H2Title, + IconButton, + IconMail, + IconReload, + IconTrash, + Status, + TooltipDelay, +} from 'twenty-ui'; + import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; @@ -16,25 +33,9 @@ import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { WorkspaceInviteLink } from '@/workspace/components/WorkspaceInviteLink'; import { WorkspaceInviteTeam } from '@/workspace/components/WorkspaceInviteTeam'; -import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { isNonEmptyArray } from '@sniptt/guards'; import { formatDistanceToNow } from 'date-fns'; -import { useState } from 'react'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { - AppTooltip, - Avatar, - H2Title, - IconButton, - IconMail, - IconReload, - IconTrash, - TooltipDelay, -} from 'twenty-ui'; import { useGetWorkspaceInvitationsQuery } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; -import { Status } from '../../modules/ui/display/status/components/Status'; import { TableCell } from '../../modules/ui/layout/table/components/TableCell'; import { TableRow } from '../../modules/ui/layout/table/components/TableRow'; import { useDeleteWorkspaceInvitation } from '../../modules/workspace-invitation/hooks/useDeleteWorkspaceInvitation'; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx index a4e7ab259..e8bbc303c 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectEdit.tsx @@ -1,4 +1,12 @@ /* eslint-disable react/jsx-props-no-spreading */ +import { zodResolver } from '@hookform/resolvers/zod'; +import pick from 'lodash.pick'; +import { useEffect } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useNavigate, useParams } from 'react-router-dom'; +import { Button, H2Title, IconArchive } from 'twenty-ui'; +import { z } from 'zod'; + import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem'; import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; @@ -22,14 +30,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; -import { zodResolver } from '@hookform/resolvers/zod'; -import pick from 'lodash.pick'; -import { useEffect } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { useNavigate, useParams } from 'react-router-dom'; import { useSetRecoilState } from 'recoil'; -import { Button, H2Title, IconArchive } from 'twenty-ui'; -import { z } from 'zod'; import { computeMetadataNameFromLabelOrThrow } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils'; const objectEditFormSchema = z @@ -81,8 +82,8 @@ export const SettingsObjectEdit = () => { ) => { let values = formValues; if ( - formValues.shouldSyncLabelAndName ?? - activeObjectMetadataItem.shouldSyncLabelAndName + formValues.shouldSyncLabelAndName === true || + activeObjectMetadataItem.shouldSyncLabelAndName === true ) { values = { ...values, diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index d9be092b9..1d355f08c 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -1,3 +1,13 @@ +import { useApolloClient } from '@apollo/client'; +import { zodResolver } from '@hookform/resolvers/zod'; +import omit from 'lodash.omit'; +import pick from 'lodash.pick'; +import { useEffect } from 'react'; +import { FormProvider, useForm } from 'react-hook-form'; +import { useNavigate, useParams } from 'react-router-dom'; +import { Button, H2Title, IconArchive, IconArchiveOff } from 'twenty-ui'; +import { z } from 'zod'; + import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata'; @@ -23,15 +33,6 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; -import { useApolloClient } from '@apollo/client'; -import { zodResolver } from '@hookform/resolvers/zod'; -import omit from 'lodash.omit'; -import pick from 'lodash.pick'; -import { useEffect } from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { useNavigate, useParams } from 'react-router-dom'; -import { Button, H2Title, IconArchive, IconArchiveOff } from 'twenty-ui'; -import { z } from 'zod'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx index 017eeb5c2..b3a0a5aaf 100644 --- a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection.tsx @@ -2,7 +2,6 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useEffect } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router-dom'; -import { H2Title } from 'twenty-ui'; import { z } from 'zod'; import { useCreateOneDatabaseConnection } from '@/databases/hooks/useCreateOneDatabaseConnection'; @@ -23,6 +22,7 @@ import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/Snac import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; +import { H2Title } from 'twenty-ui'; import { CreateRemoteServerInput } from '~/generated-metadata/graphql'; const createRemoteServerInputPostgresSchema = diff --git a/packages/twenty-front/tsup.ui.index.tsx b/packages/twenty-front/tsup.ui.index.tsx index b4f76b615..043ed4405 100644 --- a/packages/twenty-front/tsup.ui.index.tsx +++ b/packages/twenty-front/tsup.ui.index.tsx @@ -2,7 +2,6 @@ import { ThemeType } from 'twenty-ui'; export { ThemeProvider } from '@emotion/react'; export * from 'twenty-ui'; - export * from './src/modules/ui/input/components/AutosizeTextInput'; export * from './src/modules/ui/input/components/Checkbox'; export * from './src/modules/ui/input/components/EntityTitleDoubleTextInput'; diff --git a/packages/twenty-ui/src/display/index.ts b/packages/twenty-ui/src/display/index.ts index 3bab15bcf..b0f67a365 100644 --- a/packages/twenty-ui/src/display/index.ts +++ b/packages/twenty-ui/src/display/index.ts @@ -46,7 +46,10 @@ export * from './icon/hooks/useIcons'; export * from './icon/providers/IconsProvider'; export * from './icon/states/iconsState'; export * from './icon/types/IconComponent'; +export * from './info/components/Info'; +export * from './status/components/Status'; export * from './tag/components/Tag'; +export * from './text/components/SeparatorLineText'; export * from './tooltip/AppTooltip'; export * from './tooltip/OverflowingTextWithTooltip'; export * from './typography/components/H1Title'; diff --git a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx b/packages/twenty-ui/src/display/info/components/Info.tsx similarity index 93% rename from packages/twenty-front/src/modules/ui/display/info/components/Info.tsx rename to packages/twenty-ui/src/display/info/components/Info.tsx index 9761daf68..d865c7b63 100644 --- a/packages/twenty-front/src/modules/ui/display/info/components/Info.tsx +++ b/packages/twenty-ui/src/display/info/components/Info.tsx @@ -1,10 +1,10 @@ import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { IconInfoCircle } from '@ui/display/icon/components/TablerIcons'; + +import { Button } from '@ui/input/button/components/Button'; import React from 'react'; import { Link } from 'react-router-dom'; -import { Button, IconInfoCircle } from 'twenty-ui'; - -import { AppPath } from '@/types/AppPath'; export type InfoAccent = 'blue' | 'danger'; export type InfoProps = { @@ -12,7 +12,7 @@ export type InfoProps = { text: string; buttonTitle?: string; onClick?: (event: React.MouseEvent) => void; - to?: AppPath; + to?: string; }; const StyledTextContainer = styled.div` diff --git a/packages/twenty-front/src/modules/ui/display/info/components/__stories__/Info.stories.tsx b/packages/twenty-ui/src/display/info/components/__stories__/Info.stories.tsx similarity index 84% rename from packages/twenty-front/src/modules/ui/display/info/components/__stories__/Info.stories.tsx rename to packages/twenty-ui/src/display/info/components/__stories__/Info.stories.tsx index 54fcdfe0b..18a4bff44 100644 --- a/packages/twenty-front/src/modules/ui/display/info/components/__stories__/Info.stories.tsx +++ b/packages/twenty-ui/src/display/info/components/__stories__/Info.stories.tsx @@ -1,7 +1,11 @@ import { Meta, StoryObj } from '@storybook/react'; -import { CatalogDecorator, CatalogStory, ComponentDecorator } from 'twenty-ui'; +import { + CatalogDecorator, + CatalogStory, + ComponentDecorator, +} from '@ui/testing'; -import { Info, InfoAccent } from '@/ui/display/info/components/Info'; +import { Info, InfoAccent } from '../Info'; const meta: Meta = { title: 'UI/Display/Info', diff --git a/packages/twenty-front/src/modules/ui/display/status/components/Status.tsx b/packages/twenty-ui/src/display/status/components/Status.tsx similarity index 91% rename from packages/twenty-front/src/modules/ui/display/status/components/Status.tsx rename to packages/twenty-ui/src/display/status/components/Status.tsx index 9a1bdaf16..7a0713573 100644 --- a/packages/twenty-front/src/modules/ui/display/status/components/Status.tsx +++ b/packages/twenty-ui/src/display/status/components/Status.tsx @@ -1,5 +1,8 @@ import styled from '@emotion/styled'; -import { Loader, ThemeColor, themeColorSchema } from 'twenty-ui'; +import { ThemeColor } from '@ui/theme'; +import { themeColorSchema } from '@ui/theme/utils/themeColorSchema'; + +import { Loader } from '@ui/feedback/loader/components/Loader'; const StyledStatus = styled.h3<{ color: ThemeColor; diff --git a/packages/twenty-front/src/modules/ui/display/status/components/__stories__/Status.stories.tsx b/packages/twenty-ui/src/display/status/components/__stories__/Status.stories.tsx similarity index 94% rename from packages/twenty-front/src/modules/ui/display/status/components/__stories__/Status.stories.tsx rename to packages/twenty-ui/src/display/status/components/__stories__/Status.stories.tsx index cd480d45a..9f98972ce 100644 --- a/packages/twenty-front/src/modules/ui/display/status/components/__stories__/Status.stories.tsx +++ b/packages/twenty-ui/src/display/status/components/__stories__/Status.stories.tsx @@ -4,9 +4,8 @@ import { CatalogDecorator, CatalogStory, ComponentDecorator, - MAIN_COLOR_NAMES, - ThemeColor, -} from 'twenty-ui'; +} from '@ui/testing'; +import { ThemeColor, MAIN_COLOR_NAMES } from '@ui/theme'; import { Status } from '../Status'; diff --git a/packages/twenty-front/src/modules/ui/display/text/components/SeparatorLineText.tsx b/packages/twenty-ui/src/display/text/components/SeparatorLineText.tsx similarity index 100% rename from packages/twenty-front/src/modules/ui/display/text/components/SeparatorLineText.tsx rename to packages/twenty-ui/src/display/text/components/SeparatorLineText.tsx diff --git a/packages/twenty-front/src/modules/ui/display/text/components/__stories__/SeparatorLineText.stories.tsx b/packages/twenty-ui/src/display/text/components/__stories__/SeparatorLineText.stories.tsx similarity index 89% rename from packages/twenty-front/src/modules/ui/display/text/components/__stories__/SeparatorLineText.stories.tsx rename to packages/twenty-ui/src/display/text/components/__stories__/SeparatorLineText.stories.tsx index 66e0cad72..d7b15a5ef 100644 --- a/packages/twenty-front/src/modules/ui/display/text/components/__stories__/SeparatorLineText.stories.tsx +++ b/packages/twenty-ui/src/display/text/components/__stories__/SeparatorLineText.stories.tsx @@ -1,5 +1,5 @@ import { Meta, StoryObj } from '@storybook/react'; -import { ComponentDecorator } from 'twenty-ui'; +import { ComponentDecorator } from '@ui/testing'; import { SeparatorLineText } from '../SeparatorLineText'; diff --git a/packages/twenty-ui/src/input/button/components/Button.tsx b/packages/twenty-ui/src/input/button/components/Button.tsx index 6a6b49b03..6487178e4 100644 --- a/packages/twenty-ui/src/input/button/components/Button.tsx +++ b/packages/twenty-ui/src/input/button/components/Button.tsx @@ -1,8 +1,8 @@ import isPropValid from '@emotion/is-prop-valid'; import { css, useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { Pill } from '@ui/components'; -import { IconComponent } from '@ui/display'; +import { Pill } from '@ui/components/Pill/Pill'; +import { IconComponent } from '@ui/display/icon/types/IconComponent'; import React from 'react'; import { Link } from 'react-router-dom'; From 9a62bed748482cf52d6d811961a88b5677bd1a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Thu, 24 Oct 2024 18:28:51 +0200 Subject: [PATCH 03/50] Fix performance test (#8036) There was a broken story due to missing context --- .../record-index/components/RecordIndexRecordChip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx index fbeddb158..51121c41c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRecordChip.tsx @@ -32,7 +32,7 @@ export const RecordIdentifierChip = ({ name={recordChipData.name} avatarType={recordChipData.avatarType} avatarUrl={recordChipData.avatarUrl ?? ''} - to={indexIdentifierUrl(record.id)} + to={indexIdentifierUrl ? indexIdentifierUrl(record.id) : undefined} variant={variant} LeftIcon={LeftIcon} LeftIconColor={LeftIconColor} From 7edfa615714df310f0d2f616f2e8317866f07057 Mon Sep 17 00:00:00 2001 From: ZiaCodes <72739794+Khaan25@users.noreply.github.com> Date: Fri, 25 Oct 2024 00:30:54 +0500 Subject: [PATCH 04/50] feat: Disable Continue Button for Invalid Email in Sign in/Sign up (#8022) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes #7967 Here's a preview of the working solution: https://github.com/user-attachments/assets/8918e0ac-c45a-48d2-ac90-004b05ec76f3 --------- Co-authored-by: Félix Malfait --- .../modules/auth/sign-in-up/components/SignInUpForm.tsx | 8 ++++++-- .../src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx index bed04b2e8..c75a35834 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx @@ -2,7 +2,10 @@ import { FooterNote } from '@/auth/sign-in-up/components/FooterNote'; import { HorizontalSeparator } from '@/auth/sign-in-up/components/HorizontalSeparator'; import { useHandleResetPassword } from '@/auth/sign-in-up/hooks/useHandleResetPassword'; import { SignInUpMode, useSignInUp } from '@/auth/sign-in-up/hooks/useSignInUp'; -import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm'; +import { + useSignInUpForm, + validationSchema, +} from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { useSignInWithGoogle } from '@/auth/sign-in-up/hooks/useSignInWithGoogle'; import { useSignInWithMicrosoft } from '@/auth/sign-in-up/hooks/useSignInWithMicrosoft'; import { SignInUpStep } from '@/auth/states/signInUpStepState'; @@ -127,7 +130,8 @@ export const SignInUpForm = () => { const isEmailStepSubmitButtonDisabledCondition = signInUpStep === SignInUpStep.Email && - (form.watch('email')?.length === 0 || shouldWaitForCaptchaToken); + (!validationSchema.shape.email.safeParse(form.watch('email')).success || + shouldWaitForCaptchaToken); // TODO: isValid is actually a proxy function. If it is not rendered the first time, react might not trigger re-renders // We make the isValid check synchronous and update a reactState to make sure this does not happen diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts index 817b27667..07e2aaf7b 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts +++ b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts @@ -1,13 +1,13 @@ +import { zodResolver } from '@hookform/resolvers/zod'; import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; import { useRecoilValue } from 'recoil'; import { z } from 'zod'; import { PASSWORD_REGEX } from '@/auth/utils/passwordRegex'; import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilledState'; -const validationSchema = z +export const validationSchema = z .object({ exist: z.boolean(), email: z.string().trim().email('Email must be a valid email'), From bf2ba25a6ec8b8e35e7e2d744a068df35903e283 Mon Sep 17 00:00:00 2001 From: Florian Liebig Date: Fri, 25 Oct 2024 11:38:30 +0200 Subject: [PATCH 05/50] Add shortcut metadata to data models & CommandMenu (#7977) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves https://github.com/twentyhq/twenty/issues/7503 --------- Co-authored-by: Félix Malfait --- .../src/generated-metadata/gql.ts | 4 ++-- .../src/generated-metadata/graphql.ts | 7 ++++-- .../GotoHotkeysEffectsProvider.tsx | 20 ++++++++++------ .../hooks/__tests__/useCommandMenu.test.tsx | 1 + .../command-menu/hooks/useCommandMenu.ts | 4 ++-- .../object-metadata/graphql/queries.ts | 1 + .../useFindManyObjectMetadataItems.ts | 2 ++ .../objectMetadataItemSchema.ts | 1 + .../1729676165199-add-object-shortcut.ts | 24 +++++++++++++++++++ .../dtos/create-object.input.ts | 5 ++++ .../dtos/object-metadata.dto.ts | 3 +++ .../dtos/update-object.input.ts | 5 ++++ .../object-metadata/object-metadata.entity.ts | 3 +++ .../decorators/workspace-entity.decorator.ts | 2 ++ ...orkspace-entity-metadata-args.interface.ts | 5 ++++ .../company.workspace-entity.ts | 1 + .../standard-objects/note.workspace-entity.ts | 1 + .../opportunity.workspace-entity.ts | 1 + .../person.workspace-entity.ts | 1 + .../standard-objects/task.workspace-entity.ts | 1 + .../workflow.workspace-entity.ts | 1 + 21 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 packages/twenty-server/src/database/typeorm/metadata/migrations/1729676165199-add-object-shortcut.ts diff --git a/packages/twenty-front/src/generated-metadata/gql.ts b/packages/twenty-front/src/generated-metadata/gql.ts index 68c28acf6..3fb617efd 100644 --- a/packages/twenty-front/src/generated-metadata/gql.ts +++ b/packages/twenty-front/src/generated-metadata/gql.ts @@ -32,7 +32,7 @@ const documents = { "\n mutation DeleteOneObjectMetadataItem($idToDelete: UUID!) {\n deleteOneObject(input: { id: $idToDelete }) {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isActive\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n }\n }\n": types.DeleteOneObjectMetadataItemDocument, "\n mutation DeleteOneFieldMetadataItem($idToDelete: UUID!) {\n deleteOneField(input: { id: $idToDelete }) {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isNullable\n createdAt\n updatedAt\n settings\n }\n }\n": types.DeleteOneFieldMetadataItemDocument, "\n mutation DeleteOneRelationMetadataItem($idToDelete: UUID!) {\n deleteOneRelation(input: { id: $idToDelete }) {\n id\n }\n }\n": types.DeleteOneRelationMetadataItemDocument, - "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, + "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shortcut\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n": types.ObjectMetadataItemsDocument, "\n fragment ServerlessFunctionFields on ServerlessFunction {\n id\n name\n description\n runtime\n syncStatus\n latestVersion\n publishedVersions\n createdAt\n updatedAt\n }\n": types.ServerlessFunctionFieldsFragmentDoc, "\n \n mutation CreateOneServerlessFunctionItem(\n $input: CreateServerlessFunctionInput!\n ) {\n createOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.CreateOneServerlessFunctionItemDocument, "\n \n mutation DeleteOneServerlessFunction($input: ServerlessFunctionIdInput!) {\n deleteOneServerlessFunction(input: $input) {\n ...ServerlessFunctionFields\n }\n }\n": types.DeleteOneServerlessFunctionDocument, @@ -138,7 +138,7 @@ export function graphql(source: "\n mutation DeleteOneRelationMetadataItem($idT /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; +export function graphql(source: "\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shortcut\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"): (typeof documents)["\n query ObjectMetadataItems(\n $objectFilter: objectFilter\n $fieldFilter: fieldFilter\n ) {\n objects(paging: { first: 1000 }, filter: $objectFilter) {\n edges {\n node {\n id\n dataSourceId\n nameSingular\n namePlural\n labelSingular\n labelPlural\n description\n icon\n isCustom\n isRemote\n isActive\n isSystem\n createdAt\n updatedAt\n labelIdentifierFieldMetadataId\n imageIdentifierFieldMetadataId\n shortcut\n shouldSyncLabelAndName\n indexMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n name\n indexWhereClause\n indexType\n isUnique\n indexFieldMetadatas(paging: { first: 100 }) {\n edges {\n node {\n id\n createdAt\n updatedAt\n order\n fieldMetadataId\n }\n }\n }\n }\n }\n }\n fields(paging: { first: 1000 }, filter: $fieldFilter) {\n edges {\n node {\n id\n type\n name\n label\n description\n icon\n isCustom\n isActive\n isSystem\n isNullable\n isUnique\n createdAt\n updatedAt\n defaultValue\n options\n settings\n relationDefinition {\n relationId\n direction\n sourceObjectMetadata {\n id\n nameSingular\n namePlural\n }\n sourceFieldMetadata {\n id\n name\n }\n targetObjectMetadata {\n id\n nameSingular\n namePlural\n }\n targetFieldMetadata {\n id\n name\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n }\n pageInfo {\n hasNextPage\n hasPreviousPage\n startCursor\n endCursor\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index e390776e9..0b02f24f9 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -196,6 +196,7 @@ export type CreateObjectInput = { nameSingular: Scalars['String']['input']; primaryKeyColumnType?: InputMaybe; primaryKeyFieldMetadataSettings?: InputMaybe; + shortcut?: InputMaybe; shouldSyncLabelAndName?: InputMaybe; }; @@ -1434,6 +1435,7 @@ export type UpdateObjectPayload = { labelSingular?: InputMaybe; namePlural?: InputMaybe; nameSingular?: InputMaybe; + shortcut?: InputMaybe; shouldSyncLabelAndName?: InputMaybe; }; @@ -1776,6 +1778,7 @@ export type Object = { labelSingular: Scalars['String']['output']; namePlural: Scalars['String']['output']; nameSingular: Scalars['String']['output']; + shortcut?: Maybe; shouldSyncLabelAndName: Scalars['Boolean']['output']; updatedAt: Scalars['DateTime']['output']; }; @@ -1963,7 +1966,7 @@ export type ObjectMetadataItemsQueryVariables = Exact<{ }>; -export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shouldSyncLabelAndName: boolean, indexMetadatas: { __typename?: 'ObjectIndexMetadatasConnection', edges: Array<{ __typename?: 'indexEdge', node: { __typename?: 'index', id: any, createdAt: any, updatedAt: any, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, indexFieldMetadatas: { __typename?: 'IndexIndexFieldMetadatasConnection', edges: Array<{ __typename?: 'indexFieldEdge', node: { __typename?: 'indexField', id: any, createdAt: any, updatedAt: any, order: number, fieldMetadataId: any } }> } } }> }, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, settings?: any | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; +export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, shortcut?: string | null, shouldSyncLabelAndName: boolean, indexMetadatas: { __typename?: 'ObjectIndexMetadatasConnection', edges: Array<{ __typename?: 'indexEdge', node: { __typename?: 'index', id: any, createdAt: any, updatedAt: any, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, indexFieldMetadatas: { __typename?: 'IndexIndexFieldMetadatasConnection', edges: Array<{ __typename?: 'indexFieldEdge', node: { __typename?: 'indexField', id: any, createdAt: any, updatedAt: any, order: number, fieldMetadataId: any } }> } } }> }, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, settings?: any | null, relationDefinition?: { __typename?: 'RelationDefinition', relationId: any, direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; export type ServerlessFunctionFieldsFragment = { __typename?: 'ServerlessFunction', id: any, name: string, description?: string | null, runtime: string, syncStatus: ServerlessFunctionSyncStatus, latestVersion?: string | null, publishedVersions: Array, createdAt: any, updatedAt: any }; @@ -2046,7 +2049,7 @@ export const UpdateOneObjectMetadataItemDocument = {"kind":"Document","definitio export const DeleteOneObjectMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneObjectMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneFieldMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneFieldMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"settings"}}]}}]}}]} as unknown as DocumentNode; export const DeleteOneRelationMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneRelationMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneRelation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idToDelete"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"shouldSyncLabelAndName"}},{"kind":"Field","name":{"kind":"Name","value":"indexMetadatas"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"indexWhereClause"}},{"kind":"Field","name":{"kind":"Name","value":"indexType"}},{"kind":"Field","name":{"kind":"Name","value":"isUnique"}},{"kind":"Field","name":{"kind":"Name","value":"indexFieldMetadatas"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"order"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"isUnique"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"settings"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ObjectMetadataItemsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ObjectMetadataItems"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"objectFilter"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"objects"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isRemote"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"shortcut"}},{"kind":"Field","name":{"kind":"Name","value":"shouldSyncLabelAndName"}},{"kind":"Field","name":{"kind":"Name","value":"indexMetadatas"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"indexWhereClause"}},{"kind":"Field","name":{"kind":"Name","value":"indexType"}},{"kind":"Field","name":{"kind":"Name","value":"isUnique"}},{"kind":"Field","name":{"kind":"Name","value":"indexFieldMetadatas"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"order"}},{"kind":"Field","name":{"kind":"Name","value":"fieldMetadataId"}}]}}]}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"fields"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1000"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fieldFilter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isSystem"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"isUnique"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"settings"}},{"kind":"Field","name":{"kind":"Name","value":"relationDefinition"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"relationId"}},{"kind":"Field","name":{"kind":"Name","value":"direction"}},{"kind":"Field","name":{"kind":"Name","value":"sourceObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"sourceFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}}]}},{"kind":"Field","name":{"kind":"Name","value":"targetFieldMetadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"hasPreviousPage"}},{"kind":"Field","name":{"kind":"Name","value":"startCursor"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; export const CreateOneServerlessFunctionItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneServerlessFunctionItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersion"}},{"kind":"Field","name":{"kind":"Name","value":"publishedVersions"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const DeleteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunctionIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ServerlessFunctionFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ServerlessFunctionFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ServerlessFunction"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"runtime"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersion"}},{"kind":"Field","name":{"kind":"Name","value":"publishedVersions"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const ExecuteOneServerlessFunctionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ExecuteOneServerlessFunction"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ExecuteServerlessFunctionInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"executeOneServerlessFunction"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"data"}},{"kind":"Field","name":{"kind":"Name","value":"duration"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx index 44267f5c3..2cc96f515 100644 --- a/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx +++ b/packages/twenty-front/src/modules/app/effect-components/GotoHotkeysEffectsProvider.tsx @@ -27,11 +27,17 @@ export const GotoHotkeysEffectsProvider = () => { ), }); - return nonSystemActiveObjectMetadataItems.map((objectMetadataItem) => ( - - )); + return nonSystemActiveObjectMetadataItems.map((objectMetadataItem) => { + if (!objectMetadataItem.shortcut) { + return null; + } + + return ( + + ); + }); }; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx index c2449c755..72bbe2e64 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx +++ b/packages/twenty-front/src/modules/command-menu/hooks/__tests__/useCommandMenu.test.tsx @@ -125,6 +125,7 @@ describe('useCommandMenu', () => { labelSingular: 'Task', labelPlural: 'Tasks', shouldSyncLabelAndName: true, + shortcut: 'T', description: 'A task', icon: 'IconCheckbox', isCustom: false, diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts index d19c314a1..e372251a1 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCommandMenu.ts @@ -83,8 +83,8 @@ export const useCommandMenu = () => { to: `/objects/${item.namePlural}`, label: `Go to ${item.labelPlural}`, type: CommandType.Navigate, - firstHotKey: 'G', - secondHotKey: item.labelPlural[0], + firstHotKey: item.shortcut ? 'G' : undefined, + secondHotKey: item.shortcut, Icon: ALL_ICONS[ (item?.icon as keyof typeof ALL_ICONS) ?? 'IconArrowUpRight' ], diff --git a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts index 7a6a79265..bb99285d8 100644 --- a/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts +++ b/packages/twenty-front/src/modules/object-metadata/graphql/queries.ts @@ -24,6 +24,7 @@ export const FIND_MANY_OBJECT_METADATA_ITEMS = gql` updatedAt labelIdentifierFieldMetadataId imageIdentifierFieldMetadataId + shortcut shouldSyncLabelAndName indexMetadatas(paging: { first: 100 }) { edges { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems.ts index c9324a846..280d489af 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems.ts @@ -24,6 +24,8 @@ export const query = gql` updatedAt labelIdentifierFieldMetadataId imageIdentifierFieldMetadataId + shortcut + shouldSyncLabelAndName fields(paging: { first: 1000 }, filter: $fieldFilter) { edges { node { diff --git a/packages/twenty-front/src/modules/object-metadata/validation-schemas/objectMetadataItemSchema.ts b/packages/twenty-front/src/modules/object-metadata/validation-schemas/objectMetadataItemSchema.ts index 38ce3cbd1..f2b3e4e98 100644 --- a/packages/twenty-front/src/modules/object-metadata/validation-schemas/objectMetadataItemSchema.ts +++ b/packages/twenty-front/src/modules/object-metadata/validation-schemas/objectMetadataItemSchema.ts @@ -26,5 +26,6 @@ export const objectMetadataItemSchema = z.object({ namePlural: camelCaseStringSchema, nameSingular: camelCaseStringSchema, updatedAt: z.string().datetime(), + shortcut: z.string().nullable().optional(), shouldSyncLabelAndName: z.boolean(), }) satisfies z.ZodType; diff --git a/packages/twenty-server/src/database/typeorm/metadata/migrations/1729676165199-add-object-shortcut.ts b/packages/twenty-server/src/database/typeorm/metadata/migrations/1729676165199-add-object-shortcut.ts new file mode 100644 index 000000000..e1d8694d9 --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/metadata/migrations/1729676165199-add-object-shortcut.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddObjectShortcut1729676165199 implements MigrationInterface { + name = 'AddObjectShortcut1729676165199'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."objectMetadata" ADD "shortcut" character varying`, + ); + await queryRunner.query( + `CREATE UNIQUE INDEX "IDX_objectMetadata_shortcut_upper_workspace" ON "metadata"."objectMetadata" (UPPER("shortcut"), "workspaceId")`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `DROP INDEX "metadata"."IDX_objectMetadata_shortcut_upper_workspace"`, + ); + + await queryRunner.query( + `ALTER TABLE "metadata"."objectMetadata" DROP COLUMN "shortcut"`, + ); + } +} diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/create-object.input.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/create-object.input.ts index 97a7b85b7..ad877f541 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/create-object.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/create-object.input.ts @@ -51,6 +51,11 @@ export class CreateObjectInput { @Field({ nullable: true }) icon?: string; + @IsString() + @IsOptional() + @Field({ nullable: true }) + shortcut?: string; + @HideField() dataSourceId: string; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts index ad7719a32..4ab31dd48 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto.ts @@ -53,6 +53,9 @@ export class ObjectMetadataDTO { @Field({ nullable: true }) icon: string; + @Field({ nullable: true }) + shortcut: string; + @FilterableField() isCustom: boolean; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/update-object.input.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/update-object.input.ts index efb5fda4b..f977e18e0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/update-object.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/dtos/update-object.input.ts @@ -47,6 +47,11 @@ export class UpdateObjectPayload { @Field({ nullable: true }) icon?: string; + @IsString() + @IsOptional() + @Field({ nullable: true }) + shortcut?: string; + @IsBoolean() @IsOptional() @Field({ nullable: true }) diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index 7489b79e9..e636741b3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -69,6 +69,9 @@ export class ObjectMetadataEntity implements ObjectMetadataInterface { @Column({ default: true }) isAuditLogged: boolean; + @Column({ nullable: true }) + shortcut: string; + @Column({ nullable: true, type: 'uuid' }) labelIdentifierFieldMetadataId?: string | null; diff --git a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts index 5e56de140..002752642 100644 --- a/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts +++ b/packages/twenty-server/src/engine/twenty-orm/decorators/workspace-entity.decorator.ts @@ -10,6 +10,7 @@ interface WorkspaceEntityOptions { labelPlural: string; description?: string; icon?: string; + shortcut?: string; labelIdentifierStandardId?: string; imageIdentifierStandardId?: string; } @@ -44,6 +45,7 @@ export function WorkspaceEntity( options.labelIdentifierStandardId ?? BASE_OBJECT_STANDARD_FIELD_IDS.id, imageIdentifierStandardId: options.imageIdentifierStandardId ?? null, icon: options.icon, + shortcut: options.shortcut, isAuditLogged, isSystem, gate, diff --git a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts index 4cc710be2..703da6249 100644 --- a/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts +++ b/packages/twenty-server/src/engine/twenty-orm/interfaces/workspace-entity-metadata-args.interface.ts @@ -36,6 +36,11 @@ export interface WorkspaceEntityMetadataArgs { */ readonly icon?: string; + /** + * Entity shortcut. + */ + readonly shortcut?: string; + /** * Is audit logged. */ diff --git a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts index 97572f3d1..af9d0c860 100644 --- a/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts +++ b/packages/twenty-server/src/modules/company/standard-objects/company.workspace-entity.ts @@ -54,6 +54,7 @@ export const SEARCH_FIELDS_FOR_COMPANY: FieldTypeAndNameMetadata[] = [ labelPlural: 'Companies', description: 'A company', icon: 'IconBuildingSkyscraper', + shortcut: 'C', labelIdentifierStandardId: COMPANY_STANDARD_FIELD_IDS.name, }) export class CompanyWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts index 16e3fb82c..8e57cd0d8 100644 --- a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts +++ b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts @@ -44,6 +44,7 @@ export const SEARCH_FIELDS_FOR_NOTES: FieldTypeAndNameMetadata[] = [ labelPlural: 'Notes', description: 'A note', icon: 'IconNotes', + shortcut: 'N', labelIdentifierStandardId: NOTE_STANDARD_FIELD_IDS.title, }) export class NoteWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts index 22b3fae96..cf6b8e8b8 100644 --- a/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts +++ b/packages/twenty-server/src/modules/opportunity/standard-objects/opportunity.workspace-entity.ts @@ -50,6 +50,7 @@ export const SEARCH_FIELDS_FOR_OPPORTUNITY: FieldTypeAndNameMetadata[] = [ labelPlural: 'Opportunities', description: 'An opportunity', icon: 'IconTargetArrow', + shortcut: 'O', labelIdentifierStandardId: OPPORTUNITY_STANDARD_FIELD_IDS.name, }) @WorkspaceIsNotAuditLogged() diff --git a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts index fc56dbeba..f28d72220 100644 --- a/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts +++ b/packages/twenty-server/src/modules/person/standard-objects/person.workspace-entity.ts @@ -59,6 +59,7 @@ export const SEARCH_FIELDS_FOR_PERSON: FieldTypeAndNameMetadata[] = [ labelPlural: 'People', description: 'A person', icon: 'IconUser', + shortcut: 'P', labelIdentifierStandardId: PERSON_STANDARD_FIELD_IDS.name, imageIdentifierStandardId: PERSON_STANDARD_FIELD_IDS.avatarUrl, }) diff --git a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts index d498636b9..77f7b7272 100644 --- a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts +++ b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts @@ -31,6 +31,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta labelPlural: 'Tasks', description: 'A task', icon: 'IconCheckbox', + shortcut: 'T', labelIdentifierStandardId: TASK_STANDARD_FIELD_IDS.title, }) export class TaskWorkspaceEntity extends BaseWorkspaceEntity { diff --git a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts index 0ff94c934..1e05d64ac 100644 --- a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts @@ -55,6 +55,7 @@ const WorkflowStatusOptions = [ labelPlural: 'Workflows', description: 'A workflow', icon: 'IconSettingsAutomation', + shortcut: 'W', labelIdentifierStandardId: WORKFLOW_STANDARD_FIELD_IDS.name, }) @WorkspaceGate({ From 0144553667d03404865c35e13adfe8af379b9c90 Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Fri, 25 Oct 2024 14:24:56 +0200 Subject: [PATCH 06/50] Add Manual Triggers (#8024) In this PR: - Add support for manual triggers in the backend - Add a right drawer to let users select the type of trigger they want - Create a specific right drawer for database event triggers - Create a right drawer for manual triggers; let the user select where the manual trigger should be made available - Create a default trigger as soon as the user selects the type of trigger they want. It prevents the user to see empty selects for record type and event type. By default, the database event trigger will be set to "company.created". It should be visible enough for users to understand what happens and choose another record type or event type. https://github.com/user-attachments/assets/29a21985-1823-4890-9eb3-e4f876459c7a --- .../components/RightDrawerRouter.tsx | 4 + .../constants/RightDrawerPageIcons.ts | 3 +- .../constants/RightDrawerPageTitles.ts | 3 +- .../right-drawer/types/RightDrawerPages.ts | 1 + ...RightDrawerWorkflowSelectActionContent.tsx | 24 ++- .../RightDrawerWorkflowSelectTriggerType.tsx | 16 ++ ...DrawerWorkflowSelectTriggerTypeContent.tsx | 58 ++++++ .../WorkflowDiagramCanvasEditableEffect.tsx | 11 +- .../WorkflowDiagramStepNodeBase.tsx | 37 ++-- .../WorkflowEditActionFormSendEmail.tsx | 168 ++++++++---------- ...rkflowEditActionFormServerlessFunction.tsx | 64 +++---- ...se.tsx => WorkflowEditGenericFormBase.tsx} | 43 +++-- ... WorkflowEditTriggerDatabaseEventForm.tsx} | 16 +- .../WorkflowEditTriggerManualForm.tsx | 97 ++++++++++ .../components/WorkflowStepDetail.tsx | 44 ++++- .../workflow/constants/CreateStepStepId.ts | 1 + .../workflow/constants/EmptyTriggerStepId.ts | 1 + .../ManualTriggerAvailabilityOptions.ts | 19 ++ .../workflow/constants/TriggerTypes.ts | 19 ++ .../src/modules/workflow/types/Workflow.ts | 23 ++- .../modules/workflow/types/WorkflowDiagram.ts | 8 +- .../getWorkflowVersionDiagram.test.ts | 1 + .../workflow/utils/generateWorkflowDiagram.ts | 31 +++- .../utils/getManualTriggerDefaultSettings.ts | 29 +++ .../utils/getStepDefaultDefinition.ts | 3 +- .../utils/getTriggerDefaultDefinition.ts | 45 +++++ .../types/workflow-trigger.type.ts | 19 +- .../assert-version-can-be-activated.util.ts | 2 + .../workflow-trigger.workspace-service.ts | 18 +- packages/twenty-server/src/utils/assert.ts | 4 + .../display/icon/components/TablerIcons.ts | 2 + 31 files changed, 609 insertions(+), 205 deletions(-) create mode 100644 packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerType.tsx create mode 100644 packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx rename packages/twenty-front/src/modules/workflow/components/{WorkflowEditActionFormBase.tsx => WorkflowEditGenericFormBase.tsx} (54%) rename packages/twenty-front/src/modules/workflow/components/{WorkflowEditTriggerForm.tsx => WorkflowEditTriggerDatabaseEventForm.tsx} (92%) create mode 100644 packages/twenty-front/src/modules/workflow/components/WorkflowEditTriggerManualForm.tsx create mode 100644 packages/twenty-front/src/modules/workflow/constants/CreateStepStepId.ts create mode 100644 packages/twenty-front/src/modules/workflow/constants/EmptyTriggerStepId.ts create mode 100644 packages/twenty-front/src/modules/workflow/constants/ManualTriggerAvailabilityOptions.ts create mode 100644 packages/twenty-front/src/modules/workflow/constants/TriggerTypes.ts create mode 100644 packages/twenty-front/src/modules/workflow/utils/getManualTriggerDefaultSettings.ts create mode 100644 packages/twenty-front/src/modules/workflow/utils/getTriggerDefaultDefinition.ts diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx index a5640cfc0..820996bda 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/components/RightDrawerRouter.tsx @@ -15,6 +15,7 @@ import { RightDrawerWorkflowViewStep } from '@/workflow/components/RightDrawerWo import { isDefined } from 'twenty-ui'; import { rightDrawerPageState } from '../states/rightDrawerPageState'; import { RightDrawerPages } from '../types/RightDrawerPages'; +import { RightDrawerWorkflowSelectTriggerType } from '@/workflow/components/RightDrawerWorkflowSelectTriggerType'; const StyledRightDrawerPage = styled.div` display: flex; @@ -38,6 +39,9 @@ const RIGHT_DRAWER_PAGES_CONFIG: ComponentByRightDrawerPage = { [RightDrawerPages.ViewCalendarEvent]: , [RightDrawerPages.ViewRecord]: , [RightDrawerPages.Copilot]: , + [RightDrawerPages.WorkflowStepSelectTriggerType]: ( + + ), [RightDrawerPages.WorkflowStepSelectAction]: ( ), diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts index 85dc75ee1..64f594a5f 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageIcons.ts @@ -5,7 +5,8 @@ export const RIGHT_DRAWER_PAGE_ICONS = { [RightDrawerPages.ViewCalendarEvent]: 'IconCalendarEvent', [RightDrawerPages.ViewRecord]: 'Icon123', [RightDrawerPages.Copilot]: 'IconSparkles', - [RightDrawerPages.WorkflowStepEdit]: 'IconSparkles', + [RightDrawerPages.WorkflowStepSelectTriggerType]: 'IconSparkles', [RightDrawerPages.WorkflowStepSelectAction]: 'IconSparkles', + [RightDrawerPages.WorkflowStepEdit]: 'IconSparkles', [RightDrawerPages.WorkflowStepView]: 'IconSparkles', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts index 9cba79382..55e2f8899 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/constants/RightDrawerPageTitles.ts @@ -5,7 +5,8 @@ export const RIGHT_DRAWER_PAGE_TITLES = { [RightDrawerPages.ViewCalendarEvent]: 'Calendar Event', [RightDrawerPages.ViewRecord]: 'Record Editor', [RightDrawerPages.Copilot]: 'Copilot', - [RightDrawerPages.WorkflowStepEdit]: 'Workflow', + [RightDrawerPages.WorkflowStepSelectTriggerType]: 'Workflow', [RightDrawerPages.WorkflowStepSelectAction]: 'Workflow', + [RightDrawerPages.WorkflowStepEdit]: 'Workflow', [RightDrawerPages.WorkflowStepView]: 'Workflow', }; diff --git a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts index 68e20913a..1ca51cb74 100644 --- a/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts +++ b/packages/twenty-front/src/modules/ui/layout/right-drawer/types/RightDrawerPages.ts @@ -3,6 +3,7 @@ export enum RightDrawerPages { ViewCalendarEvent = 'view-calendar-event', ViewRecord = 'view-record', Copilot = 'copilot', + WorkflowStepSelectTriggerType = 'workflow-step-select-trigger-type', WorkflowStepSelectAction = 'workflow-step-select-action', WorkflowStepView = 'workflow-step-view', WorkflowStepEdit = 'workflow-step-edit', diff --git a/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectActionContent.tsx b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectActionContent.tsx index 094cc99e0..c3ac8483c 100644 --- a/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectActionContent.tsx +++ b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectActionContent.tsx @@ -24,18 +24,16 @@ export const RightDrawerWorkflowSelectActionContent = ({ }); return ( - <> - - {ACTIONS.map((action) => ( - { - return createStep(action.type); - }} - /> - ))} - - + + {ACTIONS.map((action) => ( + { + return createStep(action.type); + }} + /> + ))} + ); }; diff --git a/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerType.tsx b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerType.tsx new file mode 100644 index 000000000..7eb10fc6e --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerType.tsx @@ -0,0 +1,16 @@ +import { RightDrawerWorkflowSelectTriggerTypeContent } from '@/workflow/components/RightDrawerWorkflowSelectTriggerTypeContent'; +import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; +import { workflowIdState } from '@/workflow/states/workflowIdState'; +import { useRecoilValue } from 'recoil'; +import { isDefined } from 'twenty-ui'; + +export const RightDrawerWorkflowSelectTriggerType = () => { + const workflowId = useRecoilValue(workflowIdState); + const workflow = useWorkflowWithCurrentVersion(workflowId); + + if (!isDefined(workflow)) { + return null; + } + + return ; +}; diff --git a/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx new file mode 100644 index 000000000..daf169c27 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/RightDrawerWorkflowSelectTriggerTypeContent.tsx @@ -0,0 +1,58 @@ +import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; +import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; +import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; +import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; +import { TRIGGER_STEP_ID } from '@/workflow/constants/TriggerStepId'; +import { TRIGGER_TYPES } from '@/workflow/constants/TriggerTypes'; +import { useUpdateWorkflowVersionTrigger } from '@/workflow/hooks/useUpdateWorkflowVersionTrigger'; +import { workflowSelectedNodeState } from '@/workflow/states/workflowSelectedNodeState'; +import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow'; +import { getTriggerDefaultDefinition } from '@/workflow/utils/getTriggerDefaultDefinition'; +import styled from '@emotion/styled'; +import { useSetRecoilState } from 'recoil'; + +const StyledActionListContainer = styled.div` + display: flex; + flex-direction: column; + height: 100%; + overflow-y: auto; + + padding-block: ${({ theme }) => theme.spacing(1)}; + padding-inline: ${({ theme }) => theme.spacing(2)}; +`; + +export const RightDrawerWorkflowSelectTriggerTypeContent = ({ + workflow, +}: { + workflow: WorkflowWithCurrentVersion; +}) => { + const { updateTrigger } = useUpdateWorkflowVersionTrigger({ workflow }); + + const { activeObjectMetadataItems } = useFilteredObjectMetadataItems(); + + const { openRightDrawer } = useRightDrawer(); + const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState); + + return ( + + {TRIGGER_TYPES.map((action) => ( + { + await updateTrigger( + getTriggerDefaultDefinition({ + type: action.type, + activeObjectMetadataItems, + }), + ); + + setWorkflowSelectedNode(TRIGGER_STEP_ID); + + openRightDrawer(RightDrawerPages.WorkflowStepEdit); + }} + /> + ))} + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramCanvasEditableEffect.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramCanvasEditableEffect.tsx index ad383a527..64f3a723f 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramCanvasEditableEffect.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramCanvasEditableEffect.tsx @@ -1,5 +1,7 @@ import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages'; +import { CREATE_STEP_STEP_ID } from '@/workflow/constants/CreateStepStepId'; +import { EMPTY_TRIGGER_STEP_ID } from '@/workflow/constants/EmptyTriggerStepId'; import { useStartNodeCreation } from '@/workflow/hooks/useStartNodeCreation'; import { useTriggerNodeSelection } from '@/workflow/hooks/useTriggerNodeSelection'; import { workflowSelectedNodeState } from '@/workflow/states/workflowSelectedNodeState'; @@ -26,7 +28,14 @@ export const WorkflowDiagramCanvasEditableEffect = () => { return; } - const isCreateStepNode = selectedNode.type === 'create-step'; + const isEmptyTriggerNode = selectedNode.type === EMPTY_TRIGGER_STEP_ID; + if (isEmptyTriggerNode) { + openRightDrawer(RightDrawerPages.WorkflowStepSelectTriggerType); + + return; + } + + const isCreateStepNode = selectedNode.type === CREATE_STEP_STEP_ID; if (isCreateStepNode) { if (selectedNode.data.nodeType !== 'create-step') { throw new Error('Expected selected node to be a create step node.'); diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramStepNodeBase.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramStepNodeBase.tsx index 0fc4d8591..9cef1fbb4 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramStepNodeBase.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowDiagramStepNodeBase.tsx @@ -3,7 +3,7 @@ import { WorkflowDiagramStepNodeData } from '@/workflow/types/WorkflowDiagram'; import { assertUnreachable } from '@/workflow/utils/assertUnreachable'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; -import { IconCode, IconMail, IconPlaylistAdd } from 'twenty-ui'; +import { IconCode, IconHandMove, IconMail, IconPlaylistAdd } from 'twenty-ui'; const StyledStepNodeLabelIconContainer = styled.div` align-items: center; @@ -26,17 +26,30 @@ export const WorkflowDiagramStepNodeBase = ({ const renderStepIcon = () => { switch (data.nodeType) { case 'trigger': { - return ( - - - - ); - } - case 'condition': { - return null; + switch (data.triggerType) { + case 'DATABASE_EVENT': { + return ( + + + + ); + } + case 'MANUAL': { + return ( + + + + ); + } + } + + return assertUnreachable(data.triggerType); } case 'action': { switch (data.actionType) { diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormSendEmail.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormSendEmail.tsx index 764da25a8..bbe69aa4b 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormSendEmail.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormSendEmail.tsx @@ -5,25 +5,17 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth'; import { Select, SelectOption } from '@/ui/input/components/Select'; import { TextArea } from '@/ui/input/components/TextArea'; -import { WorkflowEditActionFormBase } from '@/workflow/components/WorkflowEditActionFormBase'; -import { VariableTagInput } from '@/workflow/search-variables/components/VariableTagInput'; +import { WorkflowEditGenericFormBase } from '@/workflow/components/WorkflowEditGenericFormBase'; +import VariableTagInput from '@/workflow/search-variables/components/VariableTagInput'; import { workflowIdState } from '@/workflow/states/workflowIdState'; import { WorkflowSendEmailStep } from '@/workflow/types/Workflow'; import { useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; import { useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useRecoilValue } from 'recoil'; import { IconMail, IconPlus, isDefined } from 'twenty-ui'; import { useDebouncedCallback } from 'use-debounce'; -const StyledTriggerSettings = styled.div` - padding: ${({ theme }) => theme.spacing(6)}; - display: flex; - flex-direction: column; - row-gap: ${({ theme }) => theme.spacing(4)}; -`; - type WorkflowEditActionFormSendEmailProps = | { action: WorkflowSendEmailStep; @@ -174,87 +166,85 @@ export const WorkflowEditActionFormSendEmail = ( return ( !loading && ( - } - actionTitle="Send Email" - actionType="Email" + } + headerTitle="Send Email" + headerType="Email" > - - ( - + triggerGoogleApisOAuth({ redirectLocation: redirectUrl }), + Icon: IconPlus, + text: 'Add account', + }} + onChange={(connectedAccountId) => { + field.onChange(connectedAccountId); + handleSave(true); + }} + /> + )} + /> + ( + { + field.onChange(email); + handleSave(); + }} + /> + )} + /> + ( + { + field.onChange(email); + handleSave(); + }} + /> + )} + /> - ( -