diff --git a/packages/twenty-front/.storybook/main.ts b/packages/twenty-front/.storybook/main.ts index 3bd4d16b2..8b65348c4 100644 --- a/packages/twenty-front/.storybook/main.ts +++ b/packages/twenty-front/.storybook/main.ts @@ -51,9 +51,6 @@ const config: StorybookConfig = { return mergeConfig(config, { // Add dependencies to pre-optimization - optimizeDeps: { - exclude: ['@tabler/icons-react'], - }, }); }, }; diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx index 3b1651298..6ba39e4d9 100644 --- a/packages/twenty-front/src/App.tsx +++ b/packages/twenty-front/src/App.tsx @@ -5,7 +5,6 @@ import { Outlet, Route, RouterProvider, - Routes, useLocation, } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -24,7 +23,6 @@ import { ApolloMetadataClientProvider } from '@/object-metadata/components/Apoll import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider'; import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider'; import { AppPath } from '@/types/AppPath'; -import { SettingsPath } from '@/types/SettingsPath'; import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager'; import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope'; import { SnackBarProvider } from '@/ui/feedback/snack-bar-manager/components/SnackBarProvider'; @@ -52,39 +50,8 @@ import { CreateWorkspace } from '~/pages/onboarding/CreateWorkspace'; import { InviteTeam } from '~/pages/onboarding/InviteTeam'; import { PaymentSuccess } from '~/pages/onboarding/PaymentSuccess'; import { SyncEmails } from '~/pages/onboarding/SyncEmails'; -import { SettingsAccounts } from '~/pages/settings/accounts/SettingsAccounts'; -import { SettingsAccountsCalendars } from '~/pages/settings/accounts/SettingsAccountsCalendars'; -import { SettingsAccountsEmails } from '~/pages/settings/accounts/SettingsAccountsEmails'; -import { SettingsNewAccount } from '~/pages/settings/accounts/SettingsNewAccount'; -import { SettingsCRMMigration } from '~/pages/settings/crm-migration/SettingsCRMMigration'; -import { SettingsNewObject } from '~/pages/settings/data-model/SettingsNewObject'; -import { SettingsObjectDetailPage } from '~/pages/settings/data-model/SettingsObjectDetailPage'; -import { SettingsObjectEdit } from '~/pages/settings/data-model/SettingsObjectEdit'; -import { SettingsObjectFieldEdit } from '~/pages/settings/data-model/SettingsObjectFieldEdit'; -import { SettingsObjectNewFieldStep1 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1'; -import { SettingsObjectNewFieldStep2 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2'; -import { SettingsObjectOverview } from '~/pages/settings/data-model/SettingsObjectOverview'; -import { SettingsObjects } from '~/pages/settings/data-model/SettingsObjects'; -import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail'; -import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew'; -import { SettingsDevelopers } from '~/pages/settings/developers/SettingsDevelopers'; -import { SettingsDevelopersWebhooksDetail } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail'; -import { SettingsDevelopersWebhooksNew } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew'; -import { SettingsIntegrationDatabase } from '~/pages/settings/integrations/SettingsIntegrationDatabase'; -import { SettingsIntegrationEditDatabaseConnection } from '~/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection'; -import { SettingsIntegrationNewDatabaseConnection } from '~/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection'; -import { SettingsIntegrations } from '~/pages/settings/integrations/SettingsIntegrations'; -import { SettingsIntegrationShowDatabaseConnection } from '~/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection'; -import { SettingsAppearance } from '~/pages/settings/profile/appearance/components/SettingsAppearance'; -import { Releases } from '~/pages/settings/Releases'; -import { SettingsServerlessFunctionDetailWrapper } from '~/pages/settings/serverless-functions/SettingsServerlessFunctionDetailWrapper'; -import { SettingsServerlessFunctions } from '~/pages/settings/serverless-functions/SettingsServerlessFunctions'; -import { SettingsServerlessFunctionsNew } from '~/pages/settings/serverless-functions/SettingsServerlessFunctionsNew'; -import { SettingsBilling } from '~/pages/settings/SettingsBilling'; -import { SettingsProfile } from '~/pages/settings/SettingsProfile'; -import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace'; -import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers'; import { WorkflowShowPage } from '~/pages/workflows/WorkflowShowPage'; +import { SettingsRoutes } from '~/SettingsRoutes'; import { getPageTitleFromPath } from '~/utils/title-utils'; const ProvidersThatNeedRouterContext = () => { @@ -164,159 +131,22 @@ const createRouter = ( } /> } /> } /> - {isWorkflowEnabled === true ? ( } /> ) : null} - - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - {isBillingEnabled && ( - } - /> - )} - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - {isCRMMigrationEnabled && ( - } - /> - )} - - } - /> - } - /> - } - /> - } - /> - - } - /> - {isServerlessFunctionSettingsEnabled && ( - <> - } - /> - } - /> - } - /> - - )} - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } - /> - } /> - + } /> } /> diff --git a/packages/twenty-front/src/SettingsRoutes.tsx b/packages/twenty-front/src/SettingsRoutes.tsx new file mode 100644 index 000000000..05e852e2b --- /dev/null +++ b/packages/twenty-front/src/SettingsRoutes.tsx @@ -0,0 +1,362 @@ +import { lazy, Suspense } from 'react'; +import { Route, Routes } from 'react-router-dom'; + +import { AppPath } from '@/types/AppPath'; +import { SettingsPath } from '@/types/SettingsPath'; + +const SettingsAccountsCalendars = lazy(() => + import('~/pages/settings/accounts/SettingsAccountsCalendars').then( + (module) => ({ + default: module.SettingsAccountsCalendars, + }), + ), +); + +const SettingsAccountsEmails = lazy(() => + import('~/pages/settings/accounts/SettingsAccountsEmails').then((module) => ({ + default: module.SettingsAccountsEmails, + })), +); + +const SettingsNewAccount = lazy(() => + import('~/pages/settings/accounts/SettingsNewAccount').then((module) => ({ + default: module.SettingsNewAccount, + })), +); + +const SettingsNewObject = lazy(() => + import('~/pages/settings/data-model/SettingsNewObject').then((module) => ({ + default: module.SettingsNewObject, + })), +); + +const SettingsObjectDetailPage = lazy(() => + import('~/pages/settings/data-model/SettingsObjectDetailPage').then( + (module) => ({ + default: module.SettingsObjectDetailPage, + }), + ), +); + +const SettingsObjectOverview = lazy(() => + import('~/pages/settings/data-model/SettingsObjectOverview').then( + (module) => ({ + default: module.SettingsObjectOverview, + }), + ), +); + +const SettingsDevelopersApiKeyDetail = lazy(() => + import( + '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail' + ).then((module) => ({ + default: module.SettingsDevelopersApiKeyDetail, + })), +); + +const SettingsDevelopersApiKeysNew = lazy(() => + import( + '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew' + ).then((module) => ({ + default: module.SettingsDevelopersApiKeysNew, + })), +); + +const SettingsDevelopersWebhooksNew = lazy(() => + import( + '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew' + ).then((module) => ({ + default: module.SettingsDevelopersWebhooksNew, + })), +); + +const Releases = lazy(() => + import('~/pages/settings/Releases').then((module) => ({ + default: module.Releases, + })), +); + +const SettingsServerlessFunctions = lazy(() => + import( + '~/pages/settings/serverless-functions/SettingsServerlessFunctions' + ).then((module) => ({ default: module.SettingsServerlessFunctions })), +); + +const SettingsServerlessFunctionDetailWrapper = lazy(() => + import( + '~/pages/settings/serverless-functions/SettingsServerlessFunctionDetailWrapper' + ).then((module) => ({ + default: module.SettingsServerlessFunctionDetailWrapper, + })), +); + +const SettingsServerlessFunctionsNew = lazy(() => + import( + '~/pages/settings/serverless-functions/SettingsServerlessFunctionsNew' + ).then((module) => ({ + default: module.SettingsServerlessFunctionsNew, + })), +); + +const SettingsWorkspace = lazy(() => + import('~/pages/settings/SettingsWorkspace').then((module) => ({ + default: module.SettingsWorkspace, + })), +); + +const SettingsWorkspaceMembers = lazy(() => + import('~/pages/settings/SettingsWorkspaceMembers').then((module) => ({ + default: module.SettingsWorkspaceMembers, + })), +); + +const SettingsProfile = lazy(() => + import('~/pages/settings/SettingsProfile').then((module) => ({ + default: module.SettingsProfile, + })), +); + +const SettingsAppearance = lazy(() => + import( + '~/pages/settings/profile/appearance/components/SettingsAppearance' + ).then((module) => ({ + default: module.SettingsAppearance, + })), +); + +const SettingsAccounts = lazy(() => + import('~/pages/settings/accounts/SettingsAccounts').then((module) => ({ + default: module.SettingsAccounts, + })), +); + +const SettingsBilling = lazy(() => + import('~/pages/settings/SettingsBilling').then((module) => ({ + default: module.SettingsBilling, + })), +); + +const SettingsDevelopers = lazy(() => + import('~/pages/settings/developers/SettingsDevelopers').then((module) => ({ + default: module.SettingsDevelopers, + })), +); + +const SettingsObjectEdit = lazy(() => + import('~/pages/settings/data-model/SettingsObjectEdit').then((module) => ({ + default: module.SettingsObjectEdit, + })), +); + +const SettingsIntegrations = lazy(() => + import('~/pages/settings/integrations/SettingsIntegrations').then( + (module) => ({ + default: module.SettingsIntegrations, + }), + ), +); + +const SettingsObjects = lazy(() => + import('~/pages/settings/data-model/SettingsObjects').then((module) => ({ + default: module.SettingsObjects, + })), +); + +const SettingsDevelopersWebhooksDetail = lazy(() => + import( + '~/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail' + ).then((module) => ({ + default: module.SettingsDevelopersWebhooksDetail, + })), +); + +const SettingsIntegrationDatabase = lazy(() => + import('~/pages/settings/integrations/SettingsIntegrationDatabase').then( + (module) => ({ + default: module.SettingsIntegrationDatabase, + }), + ), +); + +const SettingsIntegrationNewDatabaseConnection = lazy(() => + import( + '~/pages/settings/integrations/SettingsIntegrationNewDatabaseConnection' + ).then((module) => ({ + default: module.SettingsIntegrationNewDatabaseConnection, + })), +); + +const SettingsIntegrationEditDatabaseConnection = lazy(() => + import( + '~/pages/settings/integrations/SettingsIntegrationEditDatabaseConnection' + ).then((module) => ({ + default: module.SettingsIntegrationEditDatabaseConnection, + })), +); + +const SettingsIntegrationShowDatabaseConnection = lazy(() => + import( + '~/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection' + ).then((module) => ({ + default: module.SettingsIntegrationShowDatabaseConnection, + })), +); + +const SettingsObjectNewFieldStep1 = lazy(() => + import( + '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1' + ).then((module) => ({ + default: module.SettingsObjectNewFieldStep1, + })), +); + +const SettingsObjectNewFieldStep2 = lazy(() => + import( + '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2' + ).then((module) => ({ + default: module.SettingsObjectNewFieldStep2, + })), +); + +const SettingsObjectFieldEdit = lazy(() => + import('~/pages/settings/data-model/SettingsObjectFieldEdit').then( + (module) => ({ + default: module.SettingsObjectFieldEdit, + }), + ), +); + +const SettingsCRMMigration = lazy(() => + import('~/pages/settings/crm-migration/SettingsCRMMigration').then( + (module) => ({ + default: module.SettingsCRMMigration, + }), + ), +); + +type SettingsRoutesProps = { + isBillingEnabled?: boolean; + isCRMMigrationEnabled?: boolean; + isServerlessFunctionSettingsEnabled?: boolean; +}; + +export const SettingsRoutes = ({ + isBillingEnabled, + isCRMMigrationEnabled, + isServerlessFunctionSettingsEnabled, +}: SettingsRoutesProps) => ( + + + } /> + } /> + } /> + } /> + } + /> + } + /> + {isBillingEnabled && ( + } /> + )} + } + /> + } /> + } /> + } + /> + } + /> + } /> + } /> + } /> + {isCRMMigrationEnabled && ( + } + /> + )} + + } + /> + } + /> + } + /> + } + /> + + } + /> + {isServerlessFunctionSettingsEnabled && ( + <> + } + /> + } + /> + } + /> + + )} + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } + /> + } /> + + +); diff --git a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx index 506920b95..16c8bf7f4 100644 --- a/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/__stories__/CommandMenu.stories.tsx @@ -82,7 +82,9 @@ export const DefaultWithoutSearch: Story = { play: async () => { const canvas = within(document.body); - expect(await canvas.findByText('Create Task')).toBeInTheDocument(); + expect( + await canvas.findByText('Create Task', undefined, { timeout: 10000 }), + ).toBeInTheDocument(); expect(await canvas.findByText('Go to People')).toBeInTheDocument(); expect(await canvas.findByText('Go to Companies')).toBeInTheDocument(); expect(await canvas.findByText('Go to Opportunities')).toBeInTheDocument(); diff --git a/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/__stories__/KeyboardShortcutMenu.stories.tsx b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/__stories__/KeyboardShortcutMenu.stories.tsx new file mode 100644 index 000000000..afcb84abe --- /dev/null +++ b/packages/twenty-front/src/modules/keyboard-shortcut-menu/components/__stories__/KeyboardShortcutMenu.stories.tsx @@ -0,0 +1,36 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { expect, within } from '@storybook/test'; + +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; + +import { useKeyboardShortcutMenu } from '@/keyboard-shortcut-menu/hooks/useKeyboardShortcutMenu'; +import { useEffect } from 'react'; +import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; +import { KeyboardShortcutMenu } from '../KeyboardShortcutMenu'; + +const meta: Meta = { + title: 'Modules/KeyboardShortcutMenu/KeyboardShortcutMenu', + component: KeyboardShortcutMenu, + decorators: [ + (Story) => { + const { openKeyboardShortcutMenu } = useKeyboardShortcutMenu(); + useEffect(() => { + openKeyboardShortcutMenu(); + }, [openKeyboardShortcutMenu]); + return ; + }, + SnackBarDecorator, + ComponentWithRouterDecorator, + ], +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async () => { + const canvas = within(document.body); + + expect(await canvas.findByText('Keyboard shortcuts')).toBeInTheDocument(); + }, +}; diff --git a/packages/twenty-front/src/modules/object-metadata/components/__stories__/ObjectMetadataNavItems.stories.tsx b/packages/twenty-front/src/modules/object-metadata/components/__stories__/NavigationDrawerSectionForObjectMetadataItems.stories.tsx similarity index 82% rename from packages/twenty-front/src/modules/object-metadata/components/__stories__/ObjectMetadataNavItems.stories.tsx rename to packages/twenty-front/src/modules/object-metadata/components/__stories__/NavigationDrawerSectionForObjectMetadataItems.stories.tsx index bb5f7e982..10ed4d553 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/__stories__/ObjectMetadataNavItems.stories.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/__stories__/NavigationDrawerSectionForObjectMetadataItems.stories.tsx @@ -1,6 +1,4 @@ -import { expect } from '@storybook/jest'; import { Meta, StoryObj } from '@storybook/react'; -import { within } from '@storybook/test'; import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator'; import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; @@ -10,6 +8,7 @@ import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems'; +import { within } from '@storybook/test'; import { PrefetchLoadedDecorator } from '~/testing/decorators/PrefetchLoadedDecorator'; const meta: Meta = { @@ -32,10 +31,10 @@ export default meta; type Story = StoryObj; export const Default: Story = { - play: async () => { - const canvas = within(document.body); - expect(await canvas.findByText('People')).toBeInTheDocument(); - expect(await canvas.findByText('Companies')).toBeInTheDocument(); - expect(await canvas.findByText('Opportunities')).toBeInTheDocument(); + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await canvas.findByText('People', undefined, { timeout: 10000 }); + await canvas.findByText('Companies'); + await canvas.findByText('Opportunities'); }, }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx index 0a463a229..15b2daedc 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx @@ -27,6 +27,7 @@ export const ObjectFilterDropdownDateInput = () => { const [internalDate, setInternalDate] = useState( selectedFilter?.value ? new Date(selectedFilter.value) : new Date(), ); + const handleChange = (date: Date | null) => { setInternalDate(date); diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx index bf123401f..aa402d260 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect.tsx @@ -1,5 +1,5 @@ -import { useState } from 'react'; import styled from '@emotion/styled'; +import { useState } from 'react'; import { useRecoilValue } from 'recoil'; import { useIcons } from 'twenty-ui'; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx new file mode 100644 index 000000000..c09981493 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/__stories__/MultipleFiltersDropdownButton.stories.tsx @@ -0,0 +1,118 @@ +import { Meta, StoryObj } from '@storybook/react'; + +import { TaskGroups } from '@/activities/tasks/components/TaskGroups'; +import { MultipleFiltersDropdownButton } from '@/object-record/object-filter-dropdown/components/MultipleFiltersDropdownButton'; +import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; +import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope'; +import { within } from '@storybook/test'; +import { ComponentDecorator } from 'twenty-ui'; +import { FieldMetadataType } from '~/generated/graphql'; +import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator'; +import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator'; +import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; + +const meta: Meta = { + title: + 'Modules/ObjectRecord/ObjectFilterDropdown/MultipleFiltersDropdownButton', + component: MultipleFiltersDropdownButton, + decorators: [ + (Story) => { + const { setAvailableFilterDefinitions } = useFilterDropdown({ + filterDropdownId: 'entity-tasks-filter-scope', + }); + setAvailableFilterDefinitions([ + { + fieldMetadataId: '1', + iconName: 'IconUser', + label: 'Text', + type: FieldMetadataType.Text, + }, + { + fieldMetadataId: '2', + iconName: 'Icon123', + label: 'Email', + type: FieldMetadataType.Email, + }, + { + fieldMetadataId: '3', + iconName: 'IconNumber', + label: 'Number', + type: FieldMetadataType.Number, + }, + { + fieldMetadataId: '3', + iconName: 'IconCalendar', + label: 'Date', + type: FieldMetadataType.DateTime, + }, + ]); + return ( + + + + ); + }, + ObjectMetadataItemsDecorator, + SnackBarDecorator, + ComponentDecorator, + IconsProviderDecorator, + ], + args: { + hotkeyScope: { + scope: 'object-filter-dropdown', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + play: async () => { + const canvas = within(document.body); + + const filterButton = await canvas.findByText('Filter'); + + filterButton.click(); + + const textFilter = await canvas.findByText('Text'); + + textFilter.click(); + + const operatorDropdown = await canvas.findByText('Contains'); + + operatorDropdown.click(); + + const containsOption = await canvas.findByText("Doesn't contain"); + + containsOption.click(); + }, +}; + +export const Date: Story = { + play: async () => { + const canvas = within(document.body); + + const filterButton = await canvas.findByText('Filter'); + + filterButton.click(); + + const dateFilter = await canvas.findByText('Date'); + + dateFilter.click(); + }, +}; + +export const Number: Story = { + play: async () => { + const canvas = within(document.body); + + const filterButton = await canvas.findByText('Filter'); + + filterButton.click(); + + const dateFilter = await canvas.findByText('Number'); + + dateFilter.click(); + }, +}; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx index bf769c647..173612ffb 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RatingFieldDisplay.perf.stories.tsx @@ -29,6 +29,6 @@ export const Default: Story = {}; export const Performance = getProfilingStory({ componentName: 'RatingFieldDisplay', averageThresholdInMs: 0.5, - numberOfRuns: 50, + numberOfRuns: 30, numberOfTestsPerRun: 100, }); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx index 58de113f3..09c405061 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/__stories__/RelationToOneFieldInput.stories.tsx @@ -1,4 +1,3 @@ -import { useEffect } from 'react'; import { Decorator, Meta, StoryObj } from '@storybook/react'; import { expect, @@ -8,6 +7,7 @@ import { waitFor, within, } from '@storybook/test'; +import { useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; @@ -141,7 +141,9 @@ export const Submit: Story = { expect(submitJestFn).toHaveBeenCalledTimes(0); - const item = await canvas.findByText('John Wick'); + const item = await canvas.findByText('John Wick', undefined, { + timeout: 3000, + }); await waitFor(() => { userEvent.click(item); @@ -156,7 +158,7 @@ export const Cancel: Story = { const canvas = within(canvasElement); expect(cancelJestFn).toHaveBeenCalledTimes(0); - await canvas.findByText('John Wick'); + await canvas.findByText('John Wick', undefined, { timeout: 3000 }); const emptyDiv = canvas.getByTestId('data-field-input-click-outside-div'); fireEvent.click(emptyDiv); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts index b32a29f9a..fe27cadc1 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useHandleToggleTrashColumnFilter.ts @@ -61,12 +61,7 @@ export const useHandleToggleTrashColumnFilter = ({ }; upsertCombinedViewFilter(newFilter); - }, [ - columnDefinitions, - objectMetadataItem, - objectNameSingular, - upsertCombinedViewFilter, - ]); + }, [columnDefinitions, objectMetadataItem, upsertCombinedViewFilter]); return handleToggleTrashColumnFilter; }; diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx index d856c37fa..fcd311e5b 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx @@ -13,6 +13,7 @@ import { isDefined } from '~/utils/isDefined'; export type TextInputProps = TextInputV2ComponentProps & { disableHotkeys?: boolean; onInputEnter?: () => void; + dataTestId?: string; focused?: boolean; }; @@ -22,6 +23,7 @@ export const TextInput = ({ onInputEnter, disableHotkeys = false, focused, + dataTestId, ...props }: TextInputProps) => { const inputRef = useRef(null); @@ -103,6 +105,7 @@ export const TextInput = ({ ref={inputRef} // eslint-disable-next-line react/jsx-props-no-spreading {...props} + dataTestId={dataTestId} onFocus={handleFocus} onBlur={handleBlur} /> diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx index ca88e8ad4..f7a5ddf8b 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInputV2.tsx @@ -127,6 +127,7 @@ export type TextInputV2ComponentProps = Omit< LeftIcon?: IconComponent; onKeyDown?: (event: React.KeyboardEvent) => void; onBlur?: FocusEventHandler; + dataTestId?: string; }; const TextInputV2Component = ( @@ -151,6 +152,7 @@ const TextInputV2Component = ( LeftIcon, autoComplete, maxLength, + dataTestId, }: TextInputV2ComponentProps, // eslint-disable-next-line @nx/workspace-component-props-naming ref: ForwardedRef, @@ -178,6 +180,7 @@ const TextInputV2Component = ( )} { const isLoggedIn = useIsLogged(); const onboardingStatus = useOnboardingStatus(); const subscriptionStatus = useSubscriptionStatus(); + const isDefaultLayoutAuthModalVisible = useRecoilValue( isDefaultLayoutAuthModalVisibleState, ); + return useMemo(() => { if (isMatchingLocation(AppPath.Verify)) { return false; } + if ( isMatchingLocation(AppPath.Invite) || isMatchingLocation(AppPath.ResetPassword) ) { return isDefaultLayoutAuthModalVisible; } + if ( !isLoggedIn || onboardingStatus === OnboardingStatus.PlanRequired || @@ -38,6 +42,7 @@ export const useShowAuthModal = () => { ) { return true; } + if (isMatchingLocation(AppPath.PlanRequired)) { return ( (onboardingStatus === OnboardingStatus.Completed && @@ -45,6 +50,7 @@ export const useShowAuthModal = () => { subscriptionStatus === SubscriptionStatus.Canceled ); } + return false; }, [ isLoggedIn, diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index 67cb20253..e2af7df60 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -109,6 +109,7 @@ export const ConfirmationModal = ({ {confirmationValue && (
{ const canvas = within(canvasElement); - await canvas.findByText('Join Twenty dev team'); + await canvas.findByText('Join Twenty dev team', undefined, { + timeout: 5000, + }); const continueWithEmailButton = await canvas.findByText( 'Continue With Email', diff --git a/packages/twenty-front/src/pages/not-found/__stories__/NotFound.stories.tsx b/packages/twenty-front/src/pages/not-found/__stories__/NotFound.stories.tsx index 914814e01..81a468927 100644 --- a/packages/twenty-front/src/pages/not-found/__stories__/NotFound.stories.tsx +++ b/packages/twenty-front/src/pages/not-found/__stories__/NotFound.stories.tsx @@ -1,23 +1,17 @@ import { Meta, StoryObj } from '@storybook/react'; import { within } from '@storybook/test'; -import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator'; -import { HelmetProviderDecorator } from '~/testing/decorators/HelmetProviderDecorator'; -import { PageDecoratorArgs } from '~/testing/decorators/PageDecorator'; -import { RelationPickerDecorator } from '~/testing/decorators/RelationPickerDecorator'; -import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator'; +import { + PageDecorator, + PageDecoratorArgs, +} from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { NotFound } from '../NotFound'; const meta: Meta = { title: 'Pages/NotFound/Default', component: NotFound, - decorators: [ - HelmetProviderDecorator, - ComponentWithRouterDecorator, - SnackBarDecorator, - RelationPickerDecorator, - ], + decorators: [PageDecorator], args: { routePath: '/toto-not-found', }, diff --git a/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx b/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx index 48f628dbf..5f1b8c021 100644 --- a/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx +++ b/packages/twenty-front/src/pages/object-record/__stories__/RecordShowPage.stories.tsx @@ -90,7 +90,7 @@ export const Default: Story = { // await canvas.findAllByText(peopleMock[0].name.firstName); expect( await canvas.findByText('Twenty', undefined, { - timeout: 3000, + timeout: 5000, }), ).toBeInTheDocument(); expect( diff --git a/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx b/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx index b42177fed..952a6e501 100644 --- a/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.stories.tsx +++ b/packages/twenty-front/src/pages/onboarding/__stories__/ChooseYourPlan.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'; @@ -13,7 +13,6 @@ import { } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; import { mockedOnboardingUserData } from '~/testing/mock-data/users'; -import { sleep } from '~/utils/sleep'; const meta: Meta = { title: 'Pages/Onboarding/ChooseYourPlan', @@ -70,8 +69,9 @@ export type Story = StoryObj; export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - sleep(100); - await canvas.findByText('Choose your Plan'); + await canvas.findByText('Choose your Plan', undefined, { + timeout: 3000, + }); }, }; diff --git a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectEdit.stories.tsx b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectEdit.stories.tsx index d64afb769..f1521a96d 100644 --- a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectEdit.stories.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectEdit.stories.tsx @@ -34,6 +34,6 @@ export const StandardObject: Story = { export const CustomObject: Story = { args: { - routeParams: { ':objectSlug': 'listings' }, + routeParams: { ':objectSlug': 'my-custom-objects' }, }, }; diff --git a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectNewField/SettingsObjectNewFieldStep2.stories.tsx b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectNewField/SettingsObjectNewFieldStep2.stories.tsx index 0329f1110..2cdd7b682 100644 --- a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectNewField/SettingsObjectNewFieldStep2.stories.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjectNewField/SettingsObjectNewFieldStep2.stories.tsx @@ -30,7 +30,6 @@ export type Story = StoryObj; export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - await canvas.findByText('Settings'); await canvas.findByText('Objects'); await canvas.findByText('Name and description'); diff --git a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjects.stories.tsx b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjects.stories.tsx index 4782f9f23..67fceaa13 100644 --- a/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjects.stories.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/__stories__/SettingsObjects.stories.tsx @@ -6,7 +6,6 @@ import { PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; import { graphqlMocks } from '~/testing/graphqlMocks'; -import { sleep } from '~/utils/sleep'; import { SettingsObjects } from '../SettingsObjects'; @@ -28,11 +27,6 @@ export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - await sleep(1000); - - await canvas.getByRole('heading', { - level: 2, - name: 'Objects', - }); + await canvas.findByText('Existing objects', undefined, { timeout: 5000 }); }, }; diff --git a/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx b/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx index 4428ce4e1..88e6cd7ac 100644 --- a/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx +++ b/packages/twenty-front/src/pages/settings/developers/__stories__/api-keys/SettingsDevelopersApiKeysDetail.stories.tsx @@ -1,5 +1,5 @@ import { Meta, StoryObj } from '@storybook/react'; -import { userEvent, within } from '@storybook/test'; +import { fireEvent, userEvent, within } from '@storybook/test'; import { HttpResponse, graphql } from 'msw'; import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail'; @@ -50,24 +50,29 @@ export type Story = StoryObj; export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - await canvas.findByText('Settings'); + await canvas.findByText('Developers'); await canvas.findByText('sfsfdsf API Key'); }, }; export const RegenerateApiKey: Story = { - play: async ({ canvasElement, step }) => { - const canvas = within(canvasElement); - await canvas.findByText('Settings'); + play: async ({ step }) => { + const canvas = within(document.body); + await canvas.findByText('sfsfdsf API Key', undefined, { timeout: 10000 }); + + // userEvent.dblClick(await canvas.findByDisplayValue('sfsfdsf')); await userEvent.click(await canvas.findByText('Regenerate Key')); await canvas.findByText('Cancel'); - const confirmationInput = await canvas.findByPlaceholderText('yes'); - await userEvent.click(confirmationInput); - await userEvent.keyboard('y'); - await userEvent.keyboard('e'); - await userEvent.keyboard('s'); + + const confirmationInput = await canvas.findByTestId( + 'confirmation-modal-input', + ); + + fireEvent.change(confirmationInput, { + target: { value: 'yes' }, + }); const confirmButton = await canvas.findByTestId( 'confirmation-modal-confirm-button', @@ -83,16 +88,18 @@ export const RegenerateApiKey: Story = { export const DeleteApiKey: Story = { play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); - await canvas.findByText('Settings'); + await canvas.findByText('sfsfdsf API Key'); await userEvent.click(await canvas.findByText('Delete')); await canvas.findByText('Cancel'); - const confirmationInput = await canvas.findByPlaceholderText('yes'); - await userEvent.click(confirmationInput); - await userEvent.keyboard('y'); - await userEvent.keyboard('e'); - await userEvent.keyboard('s'); + const confirmationInput = await canvas.findByTestId( + 'confirmation-modal-input', + ); + + fireEvent.change(confirmationInput, { + target: { value: 'yes' }, + }); const confirmButton = await canvas.findByTestId( 'confirmation-modal-confirm-button', diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx index 9acdead88..2011d88a9 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/SettingsServerlessFunctionsNew.tsx @@ -108,3 +108,5 @@ export const SettingsServerlessFunctionsNew = () => { ); }; + +export default SettingsServerlessFunctionsNew; diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctions.stories.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctions.stories.tsx index eb1474a8b..bc6a68db1 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctions.stories.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctions.stories.tsx @@ -1,12 +1,12 @@ -import { SettingsServerlessFunctions } from '~/pages/settings/serverless-functions/SettingsServerlessFunctions'; -import { graphqlMocks } from '~/testing/graphqlMocks'; import { Meta, StoryObj } from '@storybook/react'; +import { within } from '@storybook/test'; +import { SettingsServerlessFunctions } from '~/pages/settings/serverless-functions/SettingsServerlessFunctions'; import { PageDecorator, PageDecoratorArgs, } from '~/testing/decorators/PageDecorator'; +import { graphqlMocks } from '~/testing/graphqlMocks'; import { sleep } from '~/utils/sleep'; -import { within } from '@storybook/test'; const meta: Meta = { title: 'Pages/Settings/ServerlessFunctions/SettingsServerlessFunctions', @@ -26,7 +26,6 @@ export const Default: Story = { const canvas = within(canvasElement); await sleep(100); - await canvas.findByText('Functions'); await canvas.findByText('Add your first Function'); }, }; diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 5051ea807..971ab1597 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -58,7 +58,7 @@ export const mockedTimelineActivities: Array = [ linkedObjectMetadataId: '1ad72a42-6ab4-4474-a62a-a57cae3c0298', linkedRecordCachedName: 'New Task', linkedRecordId: 'ce40eca0-8f4b-4bba-ba91-5cbd870c64d2', - name: 'task.created', + name: 'linked-task.created', createdAt: '2023-04-26T10:12:42.33625+00:00', workspaceMember: { __typename: 'WorkspaceMember', diff --git a/packages/twenty-front/vite.config.ts b/packages/twenty-front/vite.config.ts index 4daf48a28..fbab94fd8 100644 --- a/packages/twenty-front/vite.config.ts +++ b/packages/twenty-front/vite.config.ts @@ -30,19 +30,16 @@ export default defineConfig(({ command, mode }) => { }; if (VITE_DISABLE_TYPESCRIPT_CHECKER === 'true') { - // eslint-disable-next-line no-console console.log( `VITE_DISABLE_TYPESCRIPT_CHECKER: ${VITE_DISABLE_TYPESCRIPT_CHECKER}`, ); } if (VITE_DISABLE_ESLINT_CHECKER === 'true') { - // eslint-disable-next-line no-console console.log(`VITE_DISABLE_ESLINT_CHECKER: ${VITE_DISABLE_ESLINT_CHECKER}`); } if (VITE_BUILD_SOURCEMAP === 'true') { - // eslint-disable-next-line no-console console.log(`VITE_BUILD_SOURCEMAP: ${VITE_BUILD_SOURCEMAP}`); }