Skip to content

Commit b51eb64

Browse files
Jotai 12 (#18160)
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 22bc300 commit b51eb64

File tree

538 files changed

+4674
-4137
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

538 files changed

+4674
-4137
lines changed

packages/twenty-front/jest.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const jestConfig = {
6363
global: {
6464
statements: 49.5,
6565
lines: 48,
66-
functions: 40,
66+
functions: 39.5,
6767
},
6868
},
6969
collectCoverageFrom: ['<rootDir>/src/**/*.ts'],

packages/twenty-front/src/hooks/__tests__/usePageChangeEffectNavigateLocation.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat
33
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
44
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
55
import { useParams } from 'react-router-dom';
6-
import { useRecoilValue } from 'recoil';
6+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
77
import { AppPath, SettingsPath } from 'twenty-shared/types';
88
import { getSettingsPath } from 'twenty-shared/utils';
99

@@ -63,14 +63,14 @@ const setupMockUseParams = (objectNamePlural?: string) => {
6363
.mockReturnValueOnce({ objectNamePlural: objectNamePlural ?? '' });
6464
};
6565

66-
jest.mock('recoil');
66+
jest.mock('@/ui/utilities/state/jotai/hooks/useRecoilValueV2');
6767
const setupMockRecoil = (
6868
objectNamePlural?: string,
6969
verifyEmailRedirectPath?: string,
7070
calendarBookingPageId?: string | null,
7171
) => {
7272
jest
73-
.mocked(useRecoilValue)
73+
.mocked(useRecoilValueV2)
7474
.mockReturnValueOnce(calendarBookingPageId ?? 'mock-calendar-id')
7575
.mockReturnValueOnce([{ namePlural: objectNamePlural ?? '' }])
7676
.mockReturnValueOnce(verifyEmailRedirectPath);

packages/twenty-front/src/hooks/usePageChangeEffectNavigateLocation.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCu
55
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
66
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
77
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
8+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
89
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
910
import { useLocation, useParams } from 'react-router-dom';
10-
import { useRecoilValue } from 'recoil';
1111
import { AppPath, SettingsPath } from 'twenty-shared/types';
1212
import { isDefined } from 'twenty-shared/utils';
1313
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
@@ -23,7 +23,7 @@ export const usePageChangeEffectNavigateLocation = () => {
2323
);
2424
const { defaultHomePagePath } = useDefaultHomePagePath();
2525
const location = useLocation();
26-
const calendarBookingPageId = useRecoilValue(calendarBookingPageIdState);
26+
const calendarBookingPageId = useRecoilValueV2(calendarBookingPageIdState);
2727

2828
const someMatchingLocationOf = (appPaths: AppPath[]): boolean =>
2929
appPaths.some((appPath) => isMatchingLocation(location, appPath));
@@ -45,11 +45,13 @@ export const usePageChangeEffectNavigateLocation = () => {
4545
];
4646

4747
const objectNamePlural = useParams().objectNamePlural ?? '';
48-
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
48+
const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState);
4949
const objectMetadataItem = objectMetadataItems?.find(
5050
(objectMetadataItem) => objectMetadataItem.namePlural === objectNamePlural,
5151
);
52-
const verifyEmailRedirectPath = useRecoilValue(verifyEmailRedirectPathState);
52+
const verifyEmailRedirectPath = useRecoilValueV2(
53+
verifyEmailRedirectPathState,
54+
);
5355

5456
if (
5557
(!isLoggedIn || (isLoggedIn && !isOnAWorkspace)) &&

packages/twenty-front/src/modules/action-menu/contexts/ActionMenuContextProvider.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
66
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
77
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
88
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
9-
import { useRecoilValue } from 'recoil';
9+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
1010
import { isDefined } from 'twenty-shared/utils';
1111

1212
export const ActionMenuContextProvider = ({
@@ -23,7 +23,7 @@ export const ActionMenuContextProvider = ({
2323
contextStoreCurrentObjectMetadataItemIdComponentState,
2424
);
2525

26-
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
26+
const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState);
2727

2828
const objectMetadataItem =
2929
objectMetadataItemOverride ??

packages/twenty-front/src/modules/action-menu/hooks/useShouldActionBeRegisteredParams.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPe
1616
import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView';
1717
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
1818
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
19+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
20+
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
1921
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
20-
import { useContext, useMemo } from 'react';
21-
import { useRecoilCallback, useRecoilValue } from 'recoil';
22+
import { useCallback, useContext, useMemo } from 'react';
23+
import { useRecoilValue } from 'recoil';
2224
import { isDefined } from 'twenty-shared/utils';
2325
import { FeatureFlagKey } from '~/generated-metadata/graphql';
2426

@@ -104,39 +106,33 @@ export const useShouldActionBeRegisteredParams = ({
104106

105107
const isSelectAll = contextStoreTargetedRecordsRule.mode === 'exclusion';
106108

107-
const getObjectReadPermission = useRecoilCallback(
108-
({ snapshot }) =>
109-
(objectMetadataNameSingular: string) => {
110-
return snapshot
111-
.getLoadable(
112-
objectPermissionsFamilySelector({
113-
objectNameSingular: objectMetadataNameSingular,
114-
}),
115-
)
116-
.getValue().canRead;
117-
},
109+
const getObjectReadPermission = useCallback(
110+
(objectMetadataNameSingular: string) => {
111+
return jotaiStore.get(
112+
objectPermissionsFamilySelector.selectorFamily({
113+
objectNameSingular: objectMetadataNameSingular,
114+
}),
115+
).canRead;
116+
},
118117
[],
119118
);
120119

121-
const getObjectWritePermission = useRecoilCallback(
122-
({ snapshot }) =>
123-
(objectMetadataNameSingular: string) => {
124-
return snapshot
125-
.getLoadable(
126-
objectPermissionsFamilySelector({
127-
objectNameSingular: objectMetadataNameSingular,
128-
}),
129-
)
130-
.getValue().canUpdate;
131-
},
120+
const getObjectWritePermission = useCallback(
121+
(objectMetadataNameSingular: string) => {
122+
return jotaiStore.get(
123+
objectPermissionsFamilySelector.selectorFamily({
124+
objectNameSingular: objectMetadataNameSingular,
125+
}),
126+
).canUpdate;
127+
},
132128
[],
133129
);
134130

135131
const forceRegisteredActionsByKey = useRecoilValue(
136132
forceRegisteredActionsByKeyState,
137133
);
138134

139-
const currentWorkspace = useRecoilValue(currentWorkspaceState);
135+
const currentWorkspace = useRecoilValueV2(currentWorkspaceState);
140136

141137
const isFeatureFlagEnabled = (featureFlagKey: FeatureFlagKey) => {
142138
const featureFlag = currentWorkspace?.featureFlags?.find(

packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { css, useTheme } from '@emotion/react';
22
import styled from '@emotion/styled';
33
import { t } from '@lingui/core/macro';
44
import { format } from 'date-fns';
5-
import { useRecoilValue } from 'recoil';
5+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
66
import {
77
CalendarChannelVisibility,
88
type TimelineCalendarEvent,
@@ -85,7 +85,7 @@ export const CalendarEventRow = ({
8585
className,
8686
}: CalendarEventRowProps) => {
8787
const theme = useTheme();
88-
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
88+
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
8989
const { openCalendarEventInCommandMenu } =
9090
useOpenCalendarEventInCommandMenu();
9191

packages/twenty-front/src/modules/activities/files/components/AttachmentList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { type ActivityTargetableObject } from '@/activities/types/ActivityTarget
1111
import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState';
1212
import { Modal } from '@/ui/layout/modal/components/Modal';
1313
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
14-
import { useRecoilValue } from 'recoil';
14+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
1515

1616
import { ActivityList } from '@/activities/components/ActivityList';
1717
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
@@ -135,7 +135,7 @@ export const AttachmentList = ({
135135
const [previewedAttachment, setPreviewedAttachment] =
136136
useState<Attachment | null>(null);
137137

138-
const isAttachmentPreviewEnabled = useRecoilValue(
138+
const isAttachmentPreviewEnabled = useRecoilValueV2(
139139
isAttachmentPreviewEnabledState,
140140
);
141141

packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { gql, InMemoryCache } from '@apollo/client';
22
import { MockedProvider } from '@apollo/client/testing';
33
import { act, renderHook } from '@testing-library/react';
44
import { type ReactNode } from 'react';
5+
import { Provider as JotaiProvider } from 'jotai';
56
import { RecoilRoot, useSetRecoilState } from 'recoil';
67

78
import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords';
89
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
910
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
1011
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
12+
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
1113
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
1214
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
1315
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
@@ -111,30 +113,32 @@ const task = {
111113
};
112114

113115
const Wrapper = ({ children }: { children: ReactNode }) => (
114-
<RecoilRoot>
115-
<MockedProvider cache={cache}>
116-
<JestObjectMetadataItemSetter>
117-
<SnackBarComponentInstanceContext.Provider
118-
value={{ instanceId: 'snack-bar-manager' }}
119-
>
120-
{children}
121-
</SnackBarComponentInstanceContext.Provider>
122-
</JestObjectMetadataItemSetter>
123-
</MockedProvider>
124-
</RecoilRoot>
116+
<JotaiProvider store={jotaiStore}>
117+
<RecoilRoot>
118+
<MockedProvider cache={cache}>
119+
<JestObjectMetadataItemSetter>
120+
<SnackBarComponentInstanceContext.Provider
121+
value={{ instanceId: 'snack-bar-manager' }}
122+
>
123+
{children}
124+
</SnackBarComponentInstanceContext.Provider>
125+
</JestObjectMetadataItemSetter>
126+
</MockedProvider>
127+
</RecoilRoot>
128+
</JotaiProvider>
125129
);
126130

127131
describe('useActivityTargetObjectRecords', () => {
128132
it('return targetObjects', async () => {
133+
jotaiStore.set(currentWorkspaceMemberState.atom, mockWorkspaceMembers[0]);
134+
135+
jotaiStore.set(
136+
objectMetadataItemsState.atom,
137+
generatedMockObjectMetadataItems,
138+
);
139+
129140
const { result } = renderHook(
130141
() => {
131-
const setCurrentWorkspaceMember = useSetRecoilState(
132-
currentWorkspaceMemberState,
133-
);
134-
const setObjectMetadataItems = useSetRecoilState(
135-
objectMetadataItemsState,
136-
);
137-
138142
const setRecordFromStore = useSetRecoilState(
139143
recordStoreFamilyState(task.id),
140144
);
@@ -145,17 +149,13 @@ describe('useActivityTargetObjectRecords', () => {
145149

146150
return {
147151
activityTargetObjectRecords,
148-
setCurrentWorkspaceMember,
149-
setObjectMetadataItems,
150152
setRecordFromStore,
151153
};
152154
},
153155
{ wrapper: Wrapper },
154156
);
155157

156158
act(() => {
157-
result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
158-
result.current.setObjectMetadataItems(generatedMockObjectMetadataItems);
159159
result.current.setRecordFromStore(task);
160160
});
161161

packages/twenty-front/src/modules/activities/hooks/__tests__/useOpenCreateActivityDrawer.test.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { type MockedResponse } from '@apollo/client/testing';
22
import { act, renderHook } from '@testing-library/react';
3-
import { useRecoilValue, useSetRecoilState } from 'recoil';
3+
import { useRecoilValue } from 'recoil';
44

55
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
66
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
77
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
88
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
9+
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
910
import gql from 'graphql-tag';
1011
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
1112
import { mockedTasks } from '~/testing/mock-data/tasks';
@@ -72,31 +73,27 @@ const Wrapper = getJestMetadataAndApolloMocksWrapper({
7273
const mockObjectMetadataItems = generatedMockObjectMetadataItems;
7374

7475
describe('useOpenCreateActivityDrawer', () => {
76+
beforeEach(() => {
77+
jotaiStore.set(objectMetadataItemsState.atom, mockObjectMetadataItems);
78+
});
79+
7580
it('works as expected', async () => {
7681
const { result } = renderHook(
7782
() => {
7883
const openActivityRightDrawer = useOpenCreateActivityDrawer({
7984
activityObjectNameSingular: CoreObjectNameSingular.Note,
8085
});
8186
const viewableRecordId = useRecoilValue(viewableRecordIdState);
82-
const setObjectMetadataItems = useSetRecoilState(
83-
objectMetadataItemsState,
84-
);
8587
return {
8688
openActivityRightDrawer,
8789
viewableRecordId,
88-
setObjectMetadataItems,
8990
};
9091
},
9192
{
9293
wrapper: Wrapper,
9394
},
9495
);
9596

96-
act(() => {
97-
result.current.setObjectMetadataItems(mockObjectMetadataItems);
98-
});
99-
10097
expect(result.current.viewableRecordId).toBeNull();
10198
await act(async () => {
10299
result.current.openActivityRightDrawer({

packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import { type TaskTarget } from '@/activities/types/TaskTarget';
77
import { getActivityTargetObjectRecords } from '@/activities/utils/getActivityTargetObjectRecords';
88
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
99
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
10+
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
1011
import { type Nullable } from 'twenty-shared/types';
1112
import { isDefined } from 'twenty-shared/utils';
1213

1314
export const useActivityTargetObjectRecords = (
1415
activityRecordId?: string,
1516
activityTargets?: Nullable<NoteTarget[] | TaskTarget[]>,
1617
) => {
17-
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
18+
const objectMetadataItems = useRecoilValueV2(objectMetadataItemsState);
1819

1920
const activity = useRecoilValue(
2021
recordStoreFamilyState(activityRecordId ?? ''),

0 commit comments

Comments
 (0)