From 6843a642b595573a5dfc118a0e907bbcddc8ae9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:35:45 +0200 Subject: [PATCH] 7499 refactor right drawer to have contextual actions (#7954) Closes #7499 - Modifies context store states to be component states - Introduces the concept of `mainContextStore` which will dictate the available actions inside the command K - Adds contextual actions inside the right drawer - Creates a new type of modal variant --- .../components/DeleteRecordsActionEffect.tsx | 33 +++-- .../ManageFavoritesActionEffect.tsx | 7 +- ...MultipleRecordsActionMenuEntriesSetter.tsx | 4 + .../RecordActionMenuEntriesSetter.tsx | 23 +-- .../SingleRecordActionMenuEntriesSetter.tsx | 4 + .../action-menu/components/ActionMenu.tsx | 30 ---- .../components/RecordIndexActionMenu.tsx | 35 +++++ ...nuBar.tsx => RecordIndexActionMenuBar.tsx} | 13 +- ....tsx => RecordIndexActionMenuBarEntry.tsx} | 6 +- ....tsx => RecordIndexActionMenuDropdown.tsx} | 6 +- ...ct.tsx => RecordIndexActionMenuEffect.tsx} | 9 +- .../components/RecordShowActionMenu.tsx | 31 +++++ .../components/RecordShowActionMenuBar.tsx | 16 +++ .../RecordShowActionMenuBarEntry.tsx | 53 +++++++ .../__stories__/ActionMenuBar.stories.tsx | 116 ---------------- .../RecordIndexActionMenuBar.stories.tsx | 131 ++++++++++++++++++ ...RecordIndexActionMenuBarEntry.stories.tsx} | 10 +- ...RecordIndexActionMenuDropdown.stories.tsx} | 14 +- .../RecordShowActionMenuBar.stories.tsx | 131 ++++++++++++++++++ ...tionMenuDropdownPositionComponentState.ts} | 4 +- .../action-menu/types/ActionMenuType.ts | 1 + ...nContextStoreComponentInstanceIdEffect.tsx | 22 +++ ...reCurrentObjectMetadataIdComponentState.ts | 9 ++ ...ontextStoreCurrentObjectMetadataIdState.ts | 8 -- ...contextStoreCurrentViewIdComponentState.ts | 10 ++ .../states/contextStoreCurrentViewIdState.ts | 6 - ...reNumberOfSelectedRecordsComponentState.ts | 9 ++ ...ontextStoreNumberOfSelectedRecordsState.ts | 6 - ...StoreTargetedRecordsRuleComponentState.ts} | 10 +- .../ContextStoreComponentInstanceContext.tsx | 4 + .../mainContextStoreComponentInstanceId.ts | 8 ++ .../computeContextStoreFilters.test.ts | 2 +- .../utils/computeContextStoreFilters.ts | 2 +- .../components/RecordBoardCard.tsx | 4 +- .../RecordIndexBoardDataLoaderEffect.tsx | 7 +- .../components/RecordIndexContainer.tsx | 11 +- ...textStoreNumberOfSelectedRecordsEffect.tsx | 15 +- ...tainerContextStoreObjectMetadataEffect.tsx | 8 +- .../RecordIndexTableContainerEffect.tsx | 9 +- .../hooks/__tests__/useRecordData.test.tsx | 3 +- .../options/hooks/useRecordData.ts | 7 +- .../components/RecordShowContainer.tsx | 18 ++- .../RecordShowContainerContextStoreEffect.tsx | 56 ++++++++ .../hooks/useTriggerActionMenuDropdown.ts | 4 +- .../modal/components/ConfirmationModal.tsx | 5 +- .../ui/layout/modal/components/Modal.tsx | 6 +- .../page/components/RightDrawerContainer.tsx | 52 ------- .../components/ShowPageSubContainer.tsx | 24 +--- .../components/QueryParamsViewIdEffect.tsx | 8 +- .../pages/object-record/RecordIndexPage.tsx | 15 +- .../pages/object-record/RecordShowPage.tsx | 2 - .../RecordShowPageContextStoreEffect.tsx | 57 -------- .../testing/jest/JestContextStoreSetter.tsx | 17 +-- ...taAndApolloMocksAndContextStoreWrapper.tsx | 25 ++-- .../src/theme/constants/BackgroundDark.ts | 5 +- .../src/theme/constants/BackgroundLight.ts | 5 +- 56 files changed, 718 insertions(+), 418 deletions(-) delete mode 100644 packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx create mode 100644 packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx rename packages/twenty-front/src/modules/action-menu/components/{ActionMenuBar.tsx => RecordIndexActionMenuBar.tsx} (76%) rename packages/twenty-front/src/modules/action-menu/components/{ActionMenuBarEntry.tsx => RecordIndexActionMenuBarEntry.tsx} (89%) rename packages/twenty-front/src/modules/action-menu/components/{ActionMenuDropdown.tsx => RecordIndexActionMenuDropdown.tsx} (91%) rename packages/twenty-front/src/modules/action-menu/components/{ActionMenuEffect.tsx => RecordIndexActionMenuEffect.tsx} (77%) create mode 100644 packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx create mode 100644 packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBar.tsx create mode 100644 packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBarEntry.tsx delete mode 100644 packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx create mode 100644 packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx rename packages/twenty-front/src/modules/action-menu/components/__stories__/{ActionMenuBarEntry.stories.tsx => RecordIndexActionMenuBarEntry.stories.tsx} (78%) rename packages/twenty-front/src/modules/action-menu/components/__stories__/{ActionMenuDropdown.stories.tsx => RecordIndexActionMenuDropdown.stories.tsx} (85%) create mode 100644 packages/twenty-front/src/modules/action-menu/components/__stories__/RecordShowActionMenuBar.stories.tsx rename packages/twenty-front/src/modules/action-menu/states/{actionMenuDropdownPositionComponentState.ts => recordIndexActionMenuDropdownPositionComponentState.ts} (67%) create mode 100644 packages/twenty-front/src/modules/action-menu/types/ActionMenuType.ts create mode 100644 packages/twenty-front/src/modules/context-store/components/SetMainContextStoreComponentInstanceIdEffect.tsx create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdComponentState.ts delete mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts delete mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts delete mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts rename packages/twenty-front/src/modules/context-store/states/{contextStoreTargetedRecordsRuleState.ts => contextStoreTargetedRecordsRuleComponentState.ts} (53%) create mode 100644 packages/twenty-front/src/modules/context-store/states/contexts/ContextStoreComponentInstanceContext.tsx create mode 100644 packages/twenty-front/src/modules/context-store/states/mainContextStoreComponentInstanceId.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreEffect.tsx delete mode 100644 packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx delete mode 100644 packages/twenty-front/src/pages/object-record/RecordShowPageContextStoreEffect.tsx diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx index dfa609fc05..a1f1f34f1d 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/DeleteRecordsActionEffect.tsx @@ -1,6 +1,7 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { ActionMenuType } from '@/action-menu/types/ActionMenuType'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { useFavorites } from '@/favorites/hooks/useFavorites'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; @@ -9,16 +10,19 @@ import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; +import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useCallback, useEffect, useState } from 'react'; -import { useRecoilValue } from 'recoil'; import { IconTrash, isDefined } from 'twenty-ui'; export const DeleteRecordsActionEffect = ({ position, objectMetadataItem, + actionMenuType, }: { position: number; objectMetadataItem: ObjectMetadataItem; + actionMenuType: ActionMenuType; }) => { const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); @@ -35,12 +39,12 @@ export const DeleteRecordsActionEffect = ({ const { favorites, deleteFavorite } = useFavorites(); - const contextStoreNumberOfSelectedRecords = useRecoilValue( - contextStoreNumberOfSelectedRecordsState, + const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2( + contextStoreNumberOfSelectedRecordsComponentState, ); - const contextStoreTargetedRecordsRule = useRecoilValue( - contextStoreTargetedRecordsRuleState, + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, ); const graphqlFilter = computeContextStoreFilters( @@ -53,6 +57,8 @@ export const DeleteRecordsActionEffect = ({ filter: graphqlFilter, }); + const { closeRightDrawer } = useRightDrawer(); + const handleDeleteClick = useCallback(async () => { const recordIdsToDelete = await fetchAllRecordIds(); @@ -112,10 +118,19 @@ export const DeleteRecordsActionEffect = ({ }? ${ contextStoreNumberOfSelectedRecords === 1 ? 'It' : 'They' } can be recovered from the Options menu.`} - onConfirmClick={() => handleDeleteClick()} + onConfirmClick={() => { + handleDeleteClick(); + + if (actionMenuType === 'recordShow') { + closeRightDrawer(); + } + }} deleteButtonText={`Delete ${ contextStoreNumberOfSelectedRecords > 1 ? 'Records' : 'Record' }`} + modalVariant={ + actionMenuType === 'recordShow' ? 'tertiary' : 'primary' + } /> ), }); @@ -127,8 +142,10 @@ export const DeleteRecordsActionEffect = ({ removeActionMenuEntry('delete'); }; }, [ + actionMenuType, addActionMenuEntry, canDelete, + closeRightDrawer, contextStoreNumberOfSelectedRecords, handleDeleteClick, isDeleteRecordsModalOpen, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx index 572bc23939..face480344 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/ManageFavoritesActionEffect.tsx @@ -1,8 +1,9 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useFavorites } from '@/favorites/hooks/useFavorites'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; import { IconHeart, IconHeartOff, isDefined } from 'twenty-ui'; @@ -16,8 +17,8 @@ export const ManageFavoritesActionEffect = ({ }) => { const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); - const contextStoreTargetedRecordsRule = useRecoilValue( - contextStoreTargetedRecordsRuleState, + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, ); const { favorites, createFavorite, deleteFavorite } = useFavorites(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx index ad47a1ee17..f1fcd52c9b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter.tsx @@ -1,13 +1,16 @@ import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect'; import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect'; +import { ActionMenuType } from '@/action-menu/types/ActionMenuType'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; const actionEffects = [ExportRecordsActionEffect, DeleteRecordsActionEffect]; export const MultipleRecordsActionMenuEntriesSetter = ({ objectMetadataItem, + actionMenuType, }: { objectMetadataItem: ObjectMetadataItem; + actionMenuType: ActionMenuType; }) => { return ( <> @@ -16,6 +19,7 @@ export const MultipleRecordsActionMenuEntriesSetter = ({ key={index} position={index} objectMetadataItem={objectMetadataItem} + actionMenuType={actionMenuType} /> ))} diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index acf4a9bed7..5ed405684b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -1,17 +1,22 @@ import { MultipleRecordsActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/MultipleRecordsActionMenuEntriesSetter'; import { SingleRecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { ActionMenuType } from '@/action-menu/types/ActionMenuType'; +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; -import { useRecoilValue } from 'recoil'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -export const RecordActionMenuEntriesSetter = () => { - const contextStoreNumberOfSelectedRecords = useRecoilValue( - contextStoreNumberOfSelectedRecordsState, +export const RecordActionMenuEntriesSetter = ({ + actionMenuType, +}: { + actionMenuType: ActionMenuType; +}) => { + const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2( + contextStoreNumberOfSelectedRecordsComponentState, ); - const contextStoreCurrentObjectMetadataId = useRecoilValue( - contextStoreCurrentObjectMetadataIdState, + const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2( + contextStoreCurrentObjectMetadataIdComponentState, ); const { objectMetadataItem } = useObjectMetadataItemById({ @@ -32,6 +37,7 @@ export const RecordActionMenuEntriesSetter = () => { return ( ); } @@ -39,6 +45,7 @@ export const RecordActionMenuEntriesSetter = () => { return ( ); }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx index 9c4b1d528f..7bf10746fb 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/SingleRecordActionMenuEntriesSetter.tsx @@ -1,12 +1,15 @@ import { DeleteRecordsActionEffect } from '@/action-menu/actions/record-actions/components/DeleteRecordsActionEffect'; import { ExportRecordsActionEffect } from '@/action-menu/actions/record-actions/components/ExportRecordsActionEffect'; import { ManageFavoritesActionEffect } from '@/action-menu/actions/record-actions/components/ManageFavoritesActionEffect'; +import { ActionMenuType } from '@/action-menu/types/ActionMenuType'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; export const SingleRecordActionMenuEntriesSetter = ({ objectMetadataItem, + actionMenuType, }: { objectMetadataItem: ObjectMetadataItem; + actionMenuType: ActionMenuType; }) => { const actionEffects = [ ManageFavoritesActionEffect, @@ -20,6 +23,7 @@ export const SingleRecordActionMenuEntriesSetter = ({ key={index} position={index} objectMetadataItem={objectMetadataItem} + actionMenuType={actionMenuType} /> ))} diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx deleted file mode 100644 index 92cda27cc9..0000000000 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenu.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; -import { ActionMenuBar } from '@/action-menu/components/ActionMenuBar'; -import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; -import { ActionMenuDropdown } from '@/action-menu/components/ActionMenuDropdown'; -import { ActionMenuEffect } from '@/action-menu/components/ActionMenuEffect'; -import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; -import { useRecoilValue } from 'recoil'; - -export const ActionMenu = ({ actionMenuId }: { actionMenuId: string }) => { - const contextStoreCurrentObjectMetadataId = useRecoilValue( - contextStoreCurrentObjectMetadataIdState, - ); - - return ( - <> - {contextStoreCurrentObjectMetadataId && ( - - - - - - - - )} - - ); -}; diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx new file mode 100644 index 0000000000..866303d3f5 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx @@ -0,0 +1,35 @@ +import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; +import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; +import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar'; +import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown'; +import { RecordIndexActionMenuEffect } from '@/action-menu/components/RecordIndexActionMenuEffect'; + +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; + +export const RecordIndexActionMenu = ({ + actionMenuId, +}: { + actionMenuId: string; +}) => { + const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2( + contextStoreCurrentObjectMetadataIdComponentState, + ); + + return ( + <> + {contextStoreCurrentObjectMetadataId && ( + + + + + + + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx similarity index 76% rename from packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx rename to packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx index 2fd2937408..ea0383727e 100644 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBar.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBar.tsx @@ -1,14 +1,13 @@ import styled from '@emotion/styled'; -import { ActionMenuBarEntry } from '@/action-menu/components/ActionMenuBarEntry'; +import { RecordIndexActionMenuBarEntry } from '@/action-menu/components/RecordIndexActionMenuBarEntry'; import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ActionBarHotkeyScope } from '@/action-menu/types/ActionBarHotKeyScope'; -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { BottomBar } from '@/ui/layout/bottom-bar/components/BottomBar'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { useRecoilValue } from 'recoil'; const StyledLabel = styled.div` color: ${({ theme }) => theme.font.color.tertiary}; @@ -18,9 +17,9 @@ const StyledLabel = styled.div` padding-right: ${({ theme }) => theme.spacing(2)}; `; -export const ActionMenuBar = () => { - const contextStoreNumberOfSelectedRecords = useRecoilValue( - contextStoreNumberOfSelectedRecordsState, +export const RecordIndexActionMenuBar = () => { + const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2( + contextStoreNumberOfSelectedRecordsComponentState, ); const actionMenuId = useAvailableComponentInstanceIdOrThrow( @@ -44,7 +43,7 @@ export const ActionMenuBar = () => { > {contextStoreNumberOfSelectedRecords} selected: {actionMenuEntries.map((entry, index) => ( - + ))} ); diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBarEntry.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx similarity index 89% rename from packages/twenty-front/src/modules/action-menu/components/ActionMenuBarEntry.tsx rename to packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx index 02802ec4a6..8be4747983 100644 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenuBarEntry.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuBarEntry.tsx @@ -4,7 +4,7 @@ import styled from '@emotion/styled'; import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent'; -type ActionMenuBarEntryProps = { +type RecordIndexActionMenuBarEntryProps = { entry: ActionMenuEntry; }; @@ -35,7 +35,9 @@ const StyledButtonLabel = styled.div` margin-left: ${({ theme }) => theme.spacing(1)}; `; -export const ActionMenuBarEntry = ({ entry }: ActionMenuBarEntryProps) => { +export const RecordIndexActionMenuBarEntry = ({ + entry, +}: RecordIndexActionMenuBarEntryProps) => { const theme = useTheme(); return ( ` width: auto; `; -export const ActionMenuDropdown = () => { +export const RecordIndexActionMenuDropdown = () => { const actionMenuEntries = useRecoilComponentValueV2( actionMenuEntriesComponentSelector, ); @@ -45,7 +45,7 @@ export const ActionMenuDropdown = () => { const actionMenuDropdownPosition = useRecoilValue( extractComponentState( - actionMenuDropdownPositionComponentState, + recordIndexActionMenuDropdownPositionComponentState, `action-menu-dropdown-${actionMenuId}`, ), ); diff --git a/packages/twenty-front/src/modules/action-menu/components/ActionMenuEffect.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuEffect.tsx similarity index 77% rename from packages/twenty-front/src/modules/action-menu/components/ActionMenuEffect.tsx rename to packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuEffect.tsx index 89ba0f003e..97c785af7f 100644 --- a/packages/twenty-front/src/modules/action-menu/components/ActionMenuEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenuEffect.tsx @@ -1,15 +1,16 @@ import { useActionMenu } from '@/action-menu/hooks/useActionMenu'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; import { useEffect } from 'react'; import { useRecoilValue } from 'recoil'; -export const ActionMenuEffect = () => { - const contextStoreNumberOfSelectedRecords = useRecoilValue( - contextStoreNumberOfSelectedRecordsState, +export const RecordIndexActionMenuEffect = () => { + const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2( + contextStoreNumberOfSelectedRecordsComponentState, ); const actionMenuId = useAvailableComponentInstanceIdOrThrow( diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx new file mode 100644 index 0000000000..80bbfe4e14 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx @@ -0,0 +1,31 @@ +import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; +import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; +import { RecordShowActionMenuBar } from '@/action-menu/components/RecordShowActionMenuBar'; + +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; + +export const RecordShowActionMenu = ({ + actionMenuId, +}: { + actionMenuId: string; +}) => { + const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2( + contextStoreCurrentObjectMetadataIdComponentState, + ); + + return ( + <> + {contextStoreCurrentObjectMetadataId && ( + + + + + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBar.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBar.tsx new file mode 100644 index 0000000000..c4fefcef4a --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBar.tsx @@ -0,0 +1,16 @@ +import { RecordShowActionMenuBarEntry } from '@/action-menu/components/RecordShowActionMenuBarEntry'; +import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; + +export const RecordShowActionMenuBar = () => { + const actionMenuEntries = useRecoilComponentValueV2( + actionMenuEntriesComponentSelector, + ); + return ( + <> + {actionMenuEntries.map((actionMenuEntry) => ( + + ))} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBarEntry.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBarEntry.tsx new file mode 100644 index 0000000000..debc175b7c --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuBarEntry.tsx @@ -0,0 +1,53 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; + +import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; +import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent'; + +type RecordShowActionMenuBarEntryProps = { + entry: ActionMenuEntry; +}; + +const StyledButton = styled.div<{ accent: MenuItemAccent }>` + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${(props) => + props.accent === 'danger' + ? props.theme.color.red + : props.theme.font.color.secondary}; + cursor: pointer; + display: flex; + justify-content: center; + + padding: ${({ theme }) => theme.spacing(2)}; + transition: background 0.1s ease; + user-select: none; + + &:hover { + background: ${({ theme, accent }) => + accent === 'danger' + ? theme.background.danger + : theme.background.tertiary}; + } +`; + +const StyledButtonLabel = styled.div` + font-weight: ${({ theme }) => theme.font.weight.medium}; + margin-left: ${({ theme }) => theme.spacing(1)}; +`; + +// For now, this component is the same as RecordIndexActionMenuBarEntry but they +// will probably diverge in the future +export const RecordShowActionMenuBarEntry = ({ + entry, +}: RecordShowActionMenuBarEntryProps) => { + const theme = useTheme(); + return ( + entry.onClick?.()} + > + {entry.Icon && } + {entry.label} + + ); +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx deleted file mode 100644 index b34462d8fb..0000000000 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBar.stories.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { expect, jest } from '@storybook/jest'; -import { Meta, StoryObj } from '@storybook/react'; -import { RecoilRoot } from 'recoil'; - -import { ActionMenuBar } from '@/action-menu/components/ActionMenuBar'; -import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; -import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; -import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState'; -import { userEvent, waitFor, within } from '@storybook/test'; -import { IconCheckbox, IconTrash } from 'twenty-ui'; - -const deleteMock = jest.fn(); -const markAsDoneMock = jest.fn(); - -const meta: Meta = { - title: 'Modules/ActionMenu/ActionMenuBar', - component: ActionMenuBar, - decorators: [ - (Story) => ( - { - set(contextStoreTargetedRecordsRuleState, { - mode: 'selection', - selectedRecordIds: ['1', '2', '3'], - }); - set(contextStoreNumberOfSelectedRecordsState, 3); - set( - actionMenuEntriesComponentState.atomFamily({ - instanceId: 'story-action-menu', - }), - new Map([ - [ - 'delete', - { - key: 'delete', - label: 'Delete', - position: 0, - Icon: IconTrash, - onClick: deleteMock, - }, - ], - [ - 'markAsDone', - { - key: 'markAsDone', - label: 'Mark as done', - position: 1, - Icon: IconCheckbox, - onClick: markAsDoneMock, - }, - ], - ]), - ); - set( - isBottomBarOpenedComponentState.atomFamily({ - instanceId: 'action-bar-story-action-menu', - }), - true, - ); - }} - > - - - - - ), - ], - args: { - actionMenuId: 'story-action-menu', - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - args: { - actionMenuId: 'story-action-menu', - }, -}; - -export const WithCustomSelection: Story = { - args: { - actionMenuId: 'story-action-menu', - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const selectionText = await canvas.findByText('3 selected:'); - expect(selectionText).toBeInTheDocument(); - }, -}; - -export const WithButtonClicks: Story = { - args: { - actionMenuId: 'story-action-menu', - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - - const deleteButton = await canvas.findByText('Delete'); - await userEvent.click(deleteButton); - - const markAsDoneButton = await canvas.findByText('Mark as done'); - await userEvent.click(markAsDoneButton); - - await waitFor(() => { - expect(deleteMock).toHaveBeenCalled(); - expect(markAsDoneMock).toHaveBeenCalled(); - }); - }, -}; diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx new file mode 100644 index 0000000000..f3a3eab2fd --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBar.stories.tsx @@ -0,0 +1,131 @@ +import { expect, jest } from '@storybook/jest'; +import { Meta, StoryObj } from '@storybook/react'; +import { RecoilRoot } from 'recoil'; + +import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar'; +import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState'; +import { userEvent, waitFor, within } from '@storybook/test'; +import { IconCheckbox, IconTrash } from 'twenty-ui'; + +const deleteMock = jest.fn(); +const markAsDoneMock = jest.fn(); + +const meta: Meta = { + title: 'Modules/ActionMenu/RecordIndexActionMenuBar', + component: RecordIndexActionMenuBar, + decorators: [ + (Story) => ( + + { + set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + { + mode: 'selection', + selectedRecordIds: ['1', '2', '3'], + }, + ); + set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + 3, + ); + set( + actionMenuEntriesComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + new Map([ + [ + 'delete', + { + key: 'delete', + label: 'Delete', + position: 0, + Icon: IconTrash, + onClick: deleteMock, + }, + ], + [ + 'markAsDone', + { + key: 'markAsDone', + label: 'Mark as done', + position: 1, + Icon: IconCheckbox, + onClick: markAsDoneMock, + }, + ], + ]), + ); + set( + isBottomBarOpenedComponentState.atomFamily({ + instanceId: 'action-bar-story-action-menu', + }), + true, + ); + }} + > + + + + + + ), + ], + args: { + actionMenuId: 'story-action-menu', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + actionMenuId: 'story-action-menu', + }, +}; + +export const WithCustomSelection: Story = { + args: { + actionMenuId: 'story-action-menu', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const selectionText = await canvas.findByText('3 selected:'); + expect(selectionText).toBeInTheDocument(); + }, +}; + +export const WithButtonClicks: Story = { + args: { + actionMenuId: 'story-action-menu', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const deleteButton = await canvas.findByText('Delete'); + await userEvent.click(deleteButton); + + const markAsDoneButton = await canvas.findByText('Mark as done'); + await userEvent.click(markAsDoneButton); + + await waitFor(() => { + expect(deleteMock).toHaveBeenCalled(); + expect(markAsDoneMock).toHaveBeenCalled(); + }); + }, +}; diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBarEntry.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBarEntry.stories.tsx similarity index 78% rename from packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBarEntry.stories.tsx rename to packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBarEntry.stories.tsx index a9c7b26b84..96267fed3e 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuBarEntry.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuBarEntry.stories.tsx @@ -1,19 +1,19 @@ +import { RecordIndexActionMenuBarEntry } from '@/action-menu/components/RecordIndexActionMenuBarEntry'; import { expect, jest } from '@storybook/jest'; import { Meta, StoryObj } from '@storybook/react'; import { userEvent, within } from '@storybook/testing-library'; import { ComponentDecorator, IconCheckbox, IconTrash } from 'twenty-ui'; -import { ActionMenuBarEntry } from '../ActionMenuBarEntry'; -const meta: Meta = { - title: 'Modules/ActionMenu/ActionMenuBarEntry', - component: ActionMenuBarEntry, +const meta: Meta = { + title: 'Modules/ActionMenu/RecordIndexActionMenuBarEntry', + component: RecordIndexActionMenuBarEntry, decorators: [ComponentDecorator], }; export default meta; -type Story = StoryObj; +type Story = StoryObj; const deleteMock = jest.fn(); const markAsDoneMock = jest.fn(); diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuDropdown.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx similarity index 85% rename from packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuDropdown.stories.tsx rename to packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx index 53a0714cee..bb9260755a 100644 --- a/packages/twenty-front/src/modules/action-menu/components/__stories__/ActionMenuDropdown.stories.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordIndexActionMenuDropdown.stories.tsx @@ -3,10 +3,10 @@ import { Meta, StoryObj } from '@storybook/react'; import { userEvent, within } from '@storybook/testing-library'; import { RecoilRoot } from 'recoil'; -import { ActionMenuDropdown } from '@/action-menu/components/ActionMenuDropdown'; -import { actionMenuDropdownPositionComponentState } from '@/action-menu/states/actionMenuDropdownPositionComponentState'; +import { RecordIndexActionMenuDropdown } from '@/action-menu/components/RecordIndexActionMenuDropdown'; import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; import { IconCheckbox, IconHeart, IconTrash } from 'twenty-ui'; @@ -15,16 +15,16 @@ const deleteMock = jest.fn(); const markAsDoneMock = jest.fn(); const addToFavoritesMock = jest.fn(); -const meta: Meta = { - title: 'Modules/ActionMenu/ActionMenuDropdown', - component: ActionMenuDropdown, +const meta: Meta = { + title: 'Modules/ActionMenu/RecordIndexActionMenuDropdown', + component: RecordIndexActionMenuDropdown, decorators: [ (Story) => ( { set( extractComponentState( - actionMenuDropdownPositionComponentState, + recordIndexActionMenuDropdownPositionComponentState, 'action-menu-dropdown-story', ), { x: 10, y: 10 }, @@ -87,7 +87,7 @@ const meta: Meta = { export default meta; -type Story = StoryObj; +type Story = StoryObj; export const Default: Story = { args: { diff --git a/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordShowActionMenuBar.stories.tsx b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordShowActionMenuBar.stories.tsx new file mode 100644 index 0000000000..22f1bab670 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/components/__stories__/RecordShowActionMenuBar.stories.tsx @@ -0,0 +1,131 @@ +import { expect, jest } from '@storybook/jest'; +import { Meta, StoryObj } from '@storybook/react'; +import { RecoilRoot } from 'recoil'; + +import { RecordShowActionMenuBar } from '@/action-menu/components/RecordShowActionMenuBar'; +import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState'; +import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { MenuItemAccent } from '@/ui/navigation/menu-item/types/MenuItemAccent'; +import { userEvent, waitFor, within } from '@storybook/test'; +import { + ComponentDecorator, + IconFileExport, + IconHeart, + IconTrash, +} from 'twenty-ui'; + +const deleteMock = jest.fn(); +const addToFavoritesMock = jest.fn(); +const exportMock = jest.fn(); + +const meta: Meta = { + title: 'Modules/ActionMenu/RecordShowActionMenuBar', + component: RecordShowActionMenuBar, + decorators: [ + (Story) => ( + { + set( + contextStoreTargetedRecordsRuleComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + { + mode: 'selection', + selectedRecordIds: ['1'], + }, + ); + set( + contextStoreNumberOfSelectedRecordsComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + 1, + ); + set( + actionMenuEntriesComponentState.atomFamily({ + instanceId: 'story-action-menu', + }), + new Map([ + [ + 'addToFavorites', + { + key: 'addToFavorites', + label: 'Add to favorites', + position: 0, + Icon: IconHeart, + onClick: addToFavoritesMock, + }, + ], + [ + 'export', + { + key: 'export', + label: 'Export', + position: 1, + Icon: IconFileExport, + onClick: exportMock, + }, + ], + [ + 'delete', + { + key: 'delete', + label: 'Delete', + position: 2, + Icon: IconTrash, + onClick: deleteMock, + accent: 'danger' as MenuItemAccent, + }, + ], + ]), + ); + }} + > + + + + + ), + ComponentDecorator, + ], + args: { + actionMenuId: 'story-action-menu', + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + actionMenuId: 'story-action-menu', + }, +}; + +export const WithButtonClicks: Story = { + args: { + actionMenuId: 'story-action-menu', + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + const deleteButton = await canvas.findByText('Delete'); + await userEvent.click(deleteButton); + + const addToFavoritesButton = await canvas.findByText('Add to favorites'); + await userEvent.click(addToFavoritesButton); + + const exportButton = await canvas.findByText('Export'); + await userEvent.click(exportButton); + + await waitFor(() => { + expect(deleteMock).toHaveBeenCalled(); + expect(addToFavoritesMock).toHaveBeenCalled(); + expect(exportMock).toHaveBeenCalled(); + }); + }, +}; diff --git a/packages/twenty-front/src/modules/action-menu/states/actionMenuDropdownPositionComponentState.ts b/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts similarity index 67% rename from packages/twenty-front/src/modules/action-menu/states/actionMenuDropdownPositionComponentState.ts rename to packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts index f2f8f06b13..4be2f83c5b 100644 --- a/packages/twenty-front/src/modules/action-menu/states/actionMenuDropdownPositionComponentState.ts +++ b/packages/twenty-front/src/modules/action-menu/states/recordIndexActionMenuDropdownPositionComponentState.ts @@ -1,9 +1,9 @@ import { PositionType } from '@/action-menu/types/PositionType'; import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; -export const actionMenuDropdownPositionComponentState = +export const recordIndexActionMenuDropdownPositionComponentState = createComponentState({ - key: 'actionMenuDropdownPositionComponentState', + key: 'recordIndexActionMenuDropdownPositionComponentState', defaultValue: { x: null, y: null, diff --git a/packages/twenty-front/src/modules/action-menu/types/ActionMenuType.ts b/packages/twenty-front/src/modules/action-menu/types/ActionMenuType.ts new file mode 100644 index 0000000000..a0e7d0e4b5 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/types/ActionMenuType.ts @@ -0,0 +1 @@ +export type ActionMenuType = 'recordIndex' | 'recordShow'; diff --git a/packages/twenty-front/src/modules/context-store/components/SetMainContextStoreComponentInstanceIdEffect.tsx b/packages/twenty-front/src/modules/context-store/components/SetMainContextStoreComponentInstanceIdEffect.tsx new file mode 100644 index 0000000000..b1acc25d84 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/components/SetMainContextStoreComponentInstanceIdEffect.tsx @@ -0,0 +1,22 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId'; +import { useContext, useEffect } from 'react'; +import { useSetRecoilState } from 'recoil'; + +export const SetMainContextStoreComponentInstanceIdEffect = () => { + const setMainContextStoreComponentInstanceId = useSetRecoilState( + mainContextStoreComponentInstanceIdState, + ); + + const context = useContext(ContextStoreComponentInstanceContext); + + useEffect(() => { + setMainContextStoreComponentInstanceId(context?.instanceId ?? null); + + return () => { + setMainContextStoreComponentInstanceId(null); + }; + }, [context, setMainContextStoreComponentInstanceId]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdComponentState.ts new file mode 100644 index 0000000000..9898e6c6f5 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdComponentState.ts @@ -0,0 +1,9 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const contextStoreCurrentObjectMetadataIdComponentState = + createComponentStateV2({ + key: 'contextStoreCurrentObjectMetadataIdComponentState', + defaultValue: null, + componentInstanceContext: ContextStoreComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts deleted file mode 100644 index 3227e53807..0000000000 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentObjectMetadataIdState.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createState } from 'twenty-ui'; - -export const contextStoreCurrentObjectMetadataIdState = createState< - string | null ->({ - key: 'contextStoreCurrentObjectMetadataIdState', - defaultValue: null, -}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts new file mode 100644 index 0000000000..10136c28d0 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdComponentState.ts @@ -0,0 +1,10 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const contextStoreCurrentViewIdComponentState = createComponentStateV2< + string | null +>({ + key: 'contextStoreCurrentViewIdComponentState', + defaultValue: null, + componentInstanceContext: ContextStoreComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts deleted file mode 100644 index 41af1cc135..0000000000 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreCurrentViewIdState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createState } from 'twenty-ui'; - -export const contextStoreCurrentViewIdState = createState({ - key: 'contextStoreCurrentViewIdState', - defaultValue: null, -}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts new file mode 100644 index 0000000000..54a6cb1adb --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsComponentState.ts @@ -0,0 +1,9 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; + +export const contextStoreNumberOfSelectedRecordsComponentState = + createComponentStateV2({ + key: 'contextStoreNumberOfSelectedRecordsComponentState', + defaultValue: 0, + componentInstanceContext: ContextStoreComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts deleted file mode 100644 index fb1b3544d3..0000000000 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreNumberOfSelectedRecordsState.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createState } from 'twenty-ui'; - -export const contextStoreNumberOfSelectedRecordsState = createState({ - key: 'contextStoreNumberOfSelectedRecordsState', - defaultValue: 0, -}); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts similarity index 53% rename from packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts rename to packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts index 7f71377c31..1540c05f3f 100644 --- a/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleState.ts +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreTargetedRecordsRuleComponentState.ts @@ -1,5 +1,6 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { Filter } from '@/object-record/object-filter-dropdown/types/Filter'; -import { createState } from 'twenty-ui'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; type ContextStoreTargetedRecordsRuleSelectionMode = { mode: 'selection'; @@ -16,11 +17,12 @@ export type ContextStoreTargetedRecordsRule = | ContextStoreTargetedRecordsRuleSelectionMode | ContextStoreTargetedRecordsRuleExclusionMode; -export const contextStoreTargetedRecordsRuleState = - createState({ - key: 'contextStoreTargetedRecordsRuleState', +export const contextStoreTargetedRecordsRuleComponentState = + createComponentStateV2({ + key: 'contextStoreTargetedRecordsRuleComponentState', defaultValue: { mode: 'selection', selectedRecordIds: [], }, + componentInstanceContext: ContextStoreComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/context-store/states/contexts/ContextStoreComponentInstanceContext.tsx b/packages/twenty-front/src/modules/context-store/states/contexts/ContextStoreComponentInstanceContext.tsx new file mode 100644 index 0000000000..f82a5d53b1 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contexts/ContextStoreComponentInstanceContext.tsx @@ -0,0 +1,4 @@ +import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; + +export const ContextStoreComponentInstanceContext = + createComponentInstanceContext(); diff --git a/packages/twenty-front/src/modules/context-store/states/mainContextStoreComponentInstanceId.ts b/packages/twenty-front/src/modules/context-store/states/mainContextStoreComponentInstanceId.ts new file mode 100644 index 0000000000..2e73436727 --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/mainContextStoreComponentInstanceId.ts @@ -0,0 +1,8 @@ +import { createState } from 'twenty-ui'; + +export const mainContextStoreComponentInstanceIdState = createState< + string | null +>({ + key: 'mainContextStoreComponentInstanceIdState', + defaultValue: null, +}); diff --git a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts index 689d7287d4..1c65848ede 100644 --- a/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts +++ b/packages/twenty-front/src/modules/context-store/utils/__tests__/computeContextStoreFilters.test.ts @@ -1,4 +1,4 @@ -import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; diff --git a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts index 26727fbc26..edc4e17336 100644 --- a/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts +++ b/packages/twenty-front/src/modules/context-store/utils/computeContextStoreFilters.ts @@ -1,4 +1,4 @@ -import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { turnFiltersIntoQueryFilter } from '@/object-record/record-filter/utils/turnFiltersIntoQueryFilter'; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx index 2fdffd2598..8e3c002055 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-card/components/RecordBoardCard.tsx @@ -1,5 +1,5 @@ import { useActionMenu } from '@/action-menu/hooks/useActionMenu'; -import { actionMenuDropdownPositionComponentState } from '@/action-menu/states/actionMenuDropdownPositionComponentState'; +import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; import { RecordBoardContext } from '@/object-record/record-board/contexts/RecordBoardContext'; import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates'; import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext'; @@ -188,7 +188,7 @@ export const RecordBoardCard = ({ const setActionMenuDropdownPosition = useSetRecoilState( extractComponentState( - actionMenuDropdownPositionComponentState, + recordIndexActionMenuDropdownPositionComponentState, `action-menu-dropdown-${recordBoardId}`, ), ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx index 9e8358f9e0..e034730304 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexBoardDataLoaderEffect.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useRecoilValue, useSetRecoilState } from 'recoil'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug'; import { useRecordBoard } from '@/object-record/record-board/hooks/useRecordBoard'; @@ -11,6 +11,7 @@ import { recordIndexIsCompactModeActiveState } from '@/object-record/record-inde import { recordIndexKanbanFieldMetadataIdState } from '@/object-record/record-index/states/recordIndexKanbanFieldMetadataIdState'; import { computeRecordBoardColumnDefinitionsFromObjectMetadata } from '@/object-record/utils/computeRecordBoardColumnDefinitionsFromObjectMetadata'; import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { FieldMetadataType } from '~/generated-metadata/graphql'; import { isDefined } from '~/utils/isDefined'; @@ -120,8 +121,8 @@ export const RecordIndexBoardDataLoaderEffect = ({ const selectedRecordIds = useRecoilValue(selectedRecordIdsSelector()); - const setContextStoreTargetedRecords = useSetRecoilState( - contextStoreTargetedRecordsRuleState, + const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( + contextStoreTargetedRecordsRuleComponentState, ); useEffect(() => { diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx index a28d2f26ac..1bd29294bb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainer.tsx @@ -22,8 +22,9 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record- import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider'; -import { ActionMenu } from '@/action-menu/components/ActionMenu'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActionMenu'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { ViewBar } from '@/views/components/ViewBar'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewField } from '@/views/types/ViewField'; @@ -102,8 +103,8 @@ export const RecordIndexContainer = () => { [columnDefinitions, setTableColumns], ); - const setContextStoreTargetedRecordsRule = useSetRecoilState( - contextStoreTargetedRecordsRuleState, + const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2( + contextStoreTargetedRecordsRuleComponentState, ); return ( @@ -186,7 +187,7 @@ export const RecordIndexContainer = () => { /> )} - + diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx index 2a538c542a..602ed22723 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect.tsx @@ -1,22 +1,23 @@ -import { contextStoreNumberOfSelectedRecordsState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsState'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { useFindManyParams } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useContext, useEffect } from 'react'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; export const RecordIndexContainerContextStoreNumberOfSelectedRecordsEffect = () => { - const setContextStoreNumberOfSelectedRecords = useSetRecoilState( - contextStoreNumberOfSelectedRecordsState, + const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2( + contextStoreNumberOfSelectedRecordsComponentState, ); - const contextStoreTargetedRecordsRule = useRecoilValue( - contextStoreTargetedRecordsRuleState, + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, ); const { objectNamePlural } = useContext(RecordIndexRootPropsContext); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx index c94611836a..03a02ee36f 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerContextStoreObjectMetadataEffect.tsx @@ -1,13 +1,13 @@ -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useContext, useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; export const RecordIndexContainerContextStoreObjectMetadataEffect = () => { - const setContextStoreCurrentObjectMetadataItem = useSetRecoilState( - contextStoreCurrentObjectMetadataIdState, + const setContextStoreCurrentObjectMetadataItem = useSetRecoilComponentStateV2( + contextStoreCurrentObjectMetadataIdComponentState, ); const { objectNamePlural } = useContext(RecordIndexRootPropsContext); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx index ba541ca1a6..a30c797f22 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainerEffect.tsx @@ -1,13 +1,14 @@ import { useContext, useEffect } from 'react'; -import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { useRecoilValue } from 'recoil'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { RecordIndexRootPropsContext } from '@/object-record/record-index/contexts/RecordIndexRootPropsContext'; import { useHandleToggleColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleColumnFilter'; import { useHandleToggleColumnSort } from '@/object-record/record-index/hooks/useHandleToggleColumnSort'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecordCountInCurrentView } from '@/views/hooks/useSetRecordCountInCurrentView'; export const RecordIndexTableContainerEffect = () => { @@ -73,8 +74,8 @@ export const RecordIndexTableContainerEffect = () => { ); }, [setRecordCountInCurrentView, setOnEntityCountChange]); - const setContextStoreTargetedRecords = useSetRecoilState( - contextStoreTargetedRecordsRuleState, + const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( + contextStoreTargetedRecordsRuleComponentState, ); const hasUserSelectedAllRows = useRecoilValue(hasUserSelectedAllRowsState); const selectedRowIds = useRecoilValue(selectedRowIdsSelector()); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx index 9747c2c4e9..d7dc9df12c 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useRecordData.test.tsx @@ -130,6 +130,7 @@ const mocks: MockedResponse[] = [ const WrapperWithResponse = getJestMetadataAndApolloMocksAndContextStoreWrapper( { apolloMocks: mocks, + componentInstanceId: 'recordIndexId', contextStoreTargetedRecordsRule: { mode: 'selection', selectedRecordIds: [], @@ -155,6 +156,7 @@ const graphqlEmptyResponse = [ const WrapperWithEmptyResponse = getJestMetadataAndApolloMocksAndContextStoreWrapper({ apolloMocks: graphqlEmptyResponse, + componentInstanceId: 'recordIndexId', contextStoreTargetedRecordsRule: { mode: 'selection', selectedRecordIds: [], @@ -207,7 +209,6 @@ describe('useRecordData', () => { objectMetadataItem, callback, pageSize: 30, - delayMs: 0, }), { wrapper: WrapperWithResponse }, diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts index 7c65a53105..fe08785490 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useRecordData.ts @@ -7,7 +7,7 @@ import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefin import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { isDefined } from '~/utils/isDefined'; -import { contextStoreTargetedRecordsRuleState } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; @@ -15,6 +15,7 @@ import { useRecordBoardStates } from '@/object-record/record-board/hooks/interna import { useFindManyParams } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/record-index/options/constants/ExportTableDataDefaultPageSize'; import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { ViewType } from '@/views/types/ViewType'; export const sleep = (ms: number) => @@ -75,8 +76,8 @@ export const useRecordData = ({ ); const columns = useRecoilValue(visibleTableColumnsSelector()); - const contextStoreTargetedRecordsRule = useRecoilValue( - contextStoreTargetedRecordsRuleState, + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, ); const queryFilter = computeContextStoreFilters( diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx index 01e5f42d65..075b83cd35 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainer.tsx @@ -1,7 +1,10 @@ -import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ShowPageContainer } from '@/ui/layout/page/components/ShowPageContainer'; +import { SetMainContextStoreComponentInstanceIdEffect } from '@/context-store/components/SetMainContextStoreComponentInstanceIdEffect'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { InformationBannerDeletedRecord } from '@/information-banner/components/deleted-record/InformationBannerDeletedRecord'; +import { RecordShowContainerContextStoreEffect } from '@/object-record/record-show/components/RecordShowContainerContextStoreEffect'; import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData'; import { useRecordShowContainerTabs } from '@/object-record/record-show/hooks/useRecordShowContainerTabs'; import { ShowPageSubContainer } from '@/ui/layout/show-page/components/ShowPageSubContainer'; @@ -38,7 +41,16 @@ export const RecordShowContainer = ({ ); return ( - <> + + + {!isInRightDrawer && } {recordFromStore && recordFromStore.deletedAt && ( - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreEffect.tsx b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreEffect.tsx new file mode 100644 index 0000000000..fe1c65796b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-show/components/RecordShowContainerContextStoreEffect.tsx @@ -0,0 +1,56 @@ +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; +import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; +import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; +import { useEffect } from 'react'; + +export const RecordShowContainerContextStoreEffect = ({ + recordId, + objectNameSingular, +}: { + recordId: string; + objectNameSingular: string; +}) => { + const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2( + contextStoreTargetedRecordsRuleComponentState, + ); + + const setContextStoreCurrentObjectMetadataId = useSetRecoilComponentStateV2( + contextStoreCurrentObjectMetadataIdComponentState, + ); + + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: objectNameSingular, + }); + + const setContextStoreNumberOfSelectedRecords = useSetRecoilComponentStateV2( + contextStoreNumberOfSelectedRecordsComponentState, + ); + + useEffect(() => { + setContextStoreTargetedRecordsRule({ + mode: 'selection', + selectedRecordIds: [recordId], + }); + setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id); + setContextStoreNumberOfSelectedRecords(1); + + return () => { + setContextStoreTargetedRecordsRule({ + mode: 'selection', + selectedRecordIds: [], + }); + setContextStoreCurrentObjectMetadataId(null); + setContextStoreNumberOfSelectedRecords(0); + }; + }, [ + recordId, + setContextStoreTargetedRecordsRule, + setContextStoreCurrentObjectMetadataId, + objectMetadataItem?.id, + setContextStoreNumberOfSelectedRecords, + ]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts index 0870b7bb4d..a651c22cf4 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useTriggerActionMenuDropdown.ts @@ -1,6 +1,6 @@ import { useRecoilCallback } from 'recoil'; -import { actionMenuDropdownPositionComponentState } from '@/action-menu/states/actionMenuDropdownPositionComponentState'; +import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { isBottomBarOpenedComponentState } from '@/ui/layout/bottom-bar/states/isBottomBarOpenedComponentState'; import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState'; @@ -23,7 +23,7 @@ export const useTriggerActionMenuDropdown = ({ set( extractComponentState( - actionMenuDropdownPositionComponentState, + recordIndexActionMenuDropdownPositionComponentState, `action-menu-dropdown-${recordTableId}`, ), { 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 7b75faec18..3165ebce78 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 @@ -7,7 +7,7 @@ import { useDebouncedCallback } from 'use-debounce'; import { Button, ButtonAccent } from '@/ui/input/button/components/Button'; import { TextInput } from '@/ui/input/components/TextInput'; -import { Modal } from '@/ui/layout/modal/components/Modal'; +import { Modal, ModalVariants } from '@/ui/layout/modal/components/Modal'; import { Section, SectionAlignment, @@ -26,6 +26,7 @@ export type ConfirmationModalProps = { confirmationValue?: string; confirmButtonAccent?: ButtonAccent; AdditionalButtons?: React.ReactNode; + modalVariant?: ModalVariants; }; const StyledConfirmationModal = styled(Modal)` @@ -71,6 +72,7 @@ export const ConfirmationModal = ({ confirmationPlaceholder, confirmButtonAccent = 'danger', AdditionalButtons, + modalVariant = 'primary', }: ConfirmationModalProps) => { const [inputConfirmationValue, setInputConfirmationValue] = useState(''); @@ -113,6 +115,7 @@ export const ConfirmationModal = ({ onEnter={handleEnter} isClosable={true} padding="large" + modalVariant={modalVariant} > diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx index fe7983082e..5916849250 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx @@ -94,7 +94,9 @@ const StyledBackDrop = styled(motion.div)<{ background: ${({ theme, modalVariant }) => modalVariant === 'primary' ? theme.background.overlayPrimary - : theme.background.overlaySecondary}; + : modalVariant === 'secondary' + ? theme.background.overlaySecondary + : theme.background.overlayTertiary}; display: flex; height: 100%; justify-content: center; @@ -132,7 +134,7 @@ const ModalFooter = ({ children, className }: ModalFooterProps) => ( export type ModalSize = 'small' | 'medium' | 'large'; export type ModalPadding = 'none' | 'small' | 'medium' | 'large'; -export type ModalVariants = 'primary' | 'secondary'; +export type ModalVariants = 'primary' | 'secondary' | 'tertiary'; export type ModalProps = React.PropsWithChildren & { size?: ModalSize; diff --git a/packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx b/packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx deleted file mode 100644 index 5d4c0efb7e..0000000000 --- a/packages/twenty-front/src/modules/ui/layout/page/components/RightDrawerContainer.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { ReactNode } from 'react'; -import styled from '@emotion/styled'; -import { MOBILE_VIEWPORT } from 'twenty-ui'; - -import { RightDrawer } from '@/ui/layout/right-drawer/components/RightDrawer'; - -import { PagePanel } from './PagePanel'; - -type RightDrawerContainerProps = { - children: ReactNode; -}; - -const StyledMainContainer = styled.div` - background: ${({ theme }) => theme.background.noisy}; - box-sizing: border-box; - display: flex; - flex: 1 1 auto; - flex-direction: row; - gap: ${({ theme }) => theme.spacing(2)}; - min-height: 0; - padding-bottom: ${({ theme }) => theme.spacing(3)}; - padding-right: ${({ theme }) => theme.spacing(3)}; - padding-left: 0; - width: 100%; - - @media (max-width: ${MOBILE_VIEWPORT}px) { - padding-left: ${({ theme }) => theme.spacing(3)}; - padding-bottom: 0; - } -`; - -type LeftContainerProps = { - isRightDrawerOpen?: boolean; -}; - -const StyledLeftContainer = styled.div` - display: flex; - flex-direction: column; - position: relative; - width: 100%; -`; - -export const RightDrawerContainer = ({ - children, -}: RightDrawerContainerProps) => ( - - - {children} - - - -); diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx index 29a53033ed..1c6777148f 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageSubContainer.tsx @@ -1,3 +1,4 @@ +import { RecordShowActionMenu } from '@/action-menu/components/RecordShowActionMenu'; import { Calendar } from '@/activities/calendar/components/Calendar'; import { EmailThreads } from '@/activities/emails/components/EmailThreads'; import { Attachments } from '@/activities/files/components/Attachments'; @@ -6,13 +7,11 @@ import { ObjectTasks } from '@/activities/tasks/components/ObjectTasks'; import { TimelineActivities } from '@/activities/timeline-activities/components/TimelineActivities'; import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading'; import { FieldsCard } from '@/object-record/record-show/components/FieldsCard'; import { SummaryCard } from '@/object-record/record-show/components/SummaryCard'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { Button } from '@/ui/input/button/components/Button'; import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer'; import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer'; import { SingleTabProps, TabList } from '@/ui/layout/tab/components/TabList'; @@ -25,9 +24,7 @@ import { WorkflowVersionVisualizerEffect } from '@/workflow/components/WorkflowV import { WorkflowVisualizer } from '@/workflow/components/WorkflowVisualizer'; import { WorkflowVisualizerEffect } from '@/workflow/components/WorkflowVisualizerEffect'; import styled from '@emotion/styled'; -import { useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { IconTrash } from 'twenty-ui'; const StyledShowPageRightContainer = styled.div<{ isMobile: boolean }>` display: flex; @@ -198,18 +195,6 @@ export const ShowPageSubContainer = ({ } }; - const [isDeleting, setIsDeleting] = useState(false); - - const { deleteOneRecord } = useDeleteOneRecord({ - objectNameSingular: targetableObject.targetObjectNameSingular, - }); - - const handleDelete = async () => { - setIsDeleting(true); - await deleteOneRecord(targetableObject.id); - setIsDeleting(false); - }; - const [recordFromStore] = useRecoilState( recordStoreFamilyState(targetableObject.id), ); @@ -236,12 +221,7 @@ export const ShowPageSubContainer = ({ {isInRightDrawer && recordFromStore && !recordFromStore.deletedAt && ( - + )} diff --git a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx index f306f29bd7..ced095e33a 100644 --- a/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx +++ b/packages/twenty-front/src/modules/views/components/QueryParamsViewIdEffect.tsx @@ -1,14 +1,14 @@ -import { contextStoreCurrentViewIdState } from '@/context-store/states/contextStoreCurrentViewIdState'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem'; import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView'; import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams'; import { useGetCurrentView } from '@/views/hooks/useGetCurrentView'; import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState'; import { isUndefined } from '@sniptt/guards'; import { useEffect } from 'react'; -import { useSetRecoilState } from 'recoil'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDefined } from '~/utils/isDefined'; @@ -39,8 +39,8 @@ export const QueryParamsViewIdEffect = () => { objectMetadataItemId?.id, lastVisitedObjectMetadataItemId, ); - const setContextStoreCurrentViewId = useSetRecoilState( - contextStoreCurrentViewIdState, + const setContextStoreCurrentViewId = useSetRecoilComponentStateV2( + contextStoreCurrentViewIdComponentState, ); // // TODO: scope view bar per view id if possible diff --git a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx index 854f89e060..c9352d52f0 100644 --- a/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordIndexPage.tsx @@ -1,6 +1,8 @@ import styled from '@emotion/styled'; import { useParams } from 'react-router-dom'; +import { SetMainContextStoreComponentInstanceIdEffect } from '@/context-store/components/SetMainContextStoreComponentInstanceIdEffect'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; @@ -73,9 +75,16 @@ export const RecordIndexPage = () => { - - - + + + + + + diff --git a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx index 6c83840037..8f2d489bf7 100644 --- a/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx +++ b/packages/twenty-front/src/pages/object-record/RecordShowPage.tsx @@ -12,7 +12,6 @@ import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader'; import { RecordShowPageWorkflowVersionHeader } from '@/workflow/components/RecordShowPageWorkflowVersionHeader'; import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader'; -import { RecordShowPageContextStoreEffect } from '~/pages/object-record/RecordShowPageContextStoreEffect'; import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader'; export const RecordShowPage = () => { @@ -40,7 +39,6 @@ export const RecordShowPage = () => { return ( - { - const setContextStoreTargetedRecordsRule = useSetRecoilState( - contextStoreTargetedRecordsRuleState, - ); - - const setContextStoreCurrentObjectMetadataId = useSetRecoilState( - contextStoreCurrentObjectMetadataIdState, - ); - - const { objectNameSingular } = useParams(); - - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: objectNameSingular ?? '', - }); - - const setContextStoreNumberOfSelectedRecords = useSetRecoilState( - contextStoreNumberOfSelectedRecordsState, - ); - - useEffect(() => { - setContextStoreTargetedRecordsRule({ - mode: 'selection', - selectedRecordIds: [recordId], - }); - setContextStoreCurrentObjectMetadataId(objectMetadataItem?.id); - setContextStoreNumberOfSelectedRecords(1); - - return () => { - setContextStoreTargetedRecordsRule({ - mode: 'selection', - selectedRecordIds: [], - }); - setContextStoreCurrentObjectMetadataId(null); - setContextStoreNumberOfSelectedRecords(0); - }; - }, [ - recordId, - setContextStoreTargetedRecordsRule, - setContextStoreCurrentObjectMetadataId, - objectMetadataItem?.id, - setContextStoreNumberOfSelectedRecords, - ]); - - return null; -}; diff --git a/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx index 866ebe143e..47ac02bcc8 100644 --- a/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx +++ b/packages/twenty-front/src/testing/jest/JestContextStoreSetter.tsx @@ -1,12 +1,12 @@ import { ReactNode, useEffect, useState } from 'react'; -import { useSetRecoilState } from 'recoil'; -import { contextStoreCurrentObjectMetadataIdState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdState'; +import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; import { ContextStoreTargetedRecordsRule, - contextStoreTargetedRecordsRuleState, -} from '@/context-store/states/contextStoreTargetedRecordsRuleState'; + contextStoreTargetedRecordsRuleComponentState, +} from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; export const JestContextStoreSetter = ({ contextStoreTargetedRecordsRule = { @@ -20,11 +20,12 @@ export const JestContextStoreSetter = ({ contextStoreCurrentObjectMetadataNameSingular?: string; children: ReactNode; }) => { - const setContextStoreTargetedRecordsRule = useSetRecoilState( - contextStoreTargetedRecordsRuleState, + const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2( + contextStoreTargetedRecordsRuleComponentState, ); - const setContextStoreCurrentObjectMetadataId = useSetRecoilState( - contextStoreCurrentObjectMetadataIdState, + + const setContextStoreCurrentObjectMetadataId = useSetRecoilComponentStateV2( + contextStoreCurrentObjectMetadataIdComponentState, ); const { objectMetadataItem } = useObjectMetadataItem({ diff --git a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx index e674d42821..fba19c23ba 100644 --- a/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx +++ b/packages/twenty-front/src/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper.tsx @@ -1,4 +1,5 @@ -import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleState'; +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { ContextStoreTargetedRecordsRule } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { MockedResponse } from '@apollo/client/testing'; import { ReactNode } from 'react'; import { MutableSnapshot } from 'recoil'; @@ -10,6 +11,7 @@ export const getJestMetadataAndApolloMocksAndContextStoreWrapper = ({ onInitializeRecoilSnapshot, contextStoreTargetedRecordsRule, contextStoreCurrentObjectMetadataNameSingular, + componentInstanceId, }: { apolloMocks: | readonly MockedResponse, Record>[] @@ -17,6 +19,7 @@ export const getJestMetadataAndApolloMocksAndContextStoreWrapper = ({ onInitializeRecoilSnapshot?: (snapshot: MutableSnapshot) => void; contextStoreTargetedRecordsRule?: ContextStoreTargetedRecordsRule; contextStoreCurrentObjectMetadataNameSingular?: string; + componentInstanceId: string; }) => { const Wrapper = getJestMetadataAndApolloMocksWrapper({ apolloMocks, @@ -24,14 +27,20 @@ export const getJestMetadataAndApolloMocksAndContextStoreWrapper = ({ }); return ({ children }: { children: ReactNode }) => ( - - {children} - + + {children} + + ); }; diff --git a/packages/twenty-ui/src/theme/constants/BackgroundDark.ts b/packages/twenty-ui/src/theme/constants/BackgroundDark.ts index b594cb842b..446a6d2aa4 100644 --- a/packages/twenty-ui/src/theme/constants/BackgroundDark.ts +++ b/packages/twenty-ui/src/theme/constants/BackgroundDark.ts @@ -23,8 +23,9 @@ export const BACKGROUND_DARK = { lighter: RGBA(GRAY_SCALE.gray0, 0.03), danger: RGBA(COLOR.red, 0.08), }, - overlayPrimary: RGBA(GRAY_SCALE.gray80, 0.8), - overlaySecondary: RGBA(GRAY_SCALE.gray80, 0.4), + overlayPrimary: RGBA(GRAY_SCALE.gray90, 0.8), + overlaySecondary: RGBA(GRAY_SCALE.gray90, 0.4), + overlayTertiary: RGBA(GRAY_SCALE.gray90, 0.4), radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, primaryInverted: GRAY_SCALE.gray20, diff --git a/packages/twenty-ui/src/theme/constants/BackgroundLight.ts b/packages/twenty-ui/src/theme/constants/BackgroundLight.ts index 187ecf7de8..dfd68500ae 100644 --- a/packages/twenty-ui/src/theme/constants/BackgroundLight.ts +++ b/packages/twenty-ui/src/theme/constants/BackgroundLight.ts @@ -23,8 +23,9 @@ export const BACKGROUND_LIGHT = { lighter: RGBA(GRAY_SCALE.gray100, 0.02), danger: RGBA(COLOR.red, 0.08), }, - overlayPrimary: RGBA(GRAY_SCALE.gray80, 0.8), - overlaySecondary: RGBA(GRAY_SCALE.gray80, 0.4), + overlayPrimary: RGBA(GRAY_SCALE.gray90, 0.8), + overlaySecondary: RGBA(GRAY_SCALE.gray90, 0.4), + overlayTertiary: RGBA(GRAY_SCALE.gray90, 0.08), radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${GRAY_SCALE.gray60} 100%)`, primaryInverted: GRAY_SCALE.gray60,