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}`);
}