Remove all legacy state management (#13476)

This PR removes every legacy state management logic left in the code
base, we only keep our last component state management logic.

Removed : 
- Scoped states logic
- Dropdown scope logic
- Scope id naming
- Component state v1
- Component state v2_alpha


# QA

| Component | Comments |
| --- | --- |
| AttachementDropdown | Ok |
| ObjectTasks | Ok |
| ActivityRichTextEditor | Ok |
| App | Ok dialogs work |
| AppRouterProviders | Ok dialogs work |
| RecordBoardScrollToFocusedCardEffect | Ok |
| RecordBoard | Ok |
| RecordBoardCard | OK |
| useSelectAllCards | Ok |
| RecordInlineCell | Ok |
| useInlineCell | Ok |
| RecordDetailRelationRecordsListItem | Ok |
| RecordDetailRelationSectionDropdownToMany | Ok |
| RecordDetailRelationSectionDropdownToOne | Ok |
| useHandleContainerMouseEnter | Ok |
| useResetTableRowSelection | Ok |
| useSelectAllRows | Ok |
| useSetRecordTableData | Ok |
| useRecordTable | Ok |
| useRecordTableMoveFocusedCell | Ok |
| useRecordTableMoveFocusedRow | Ok |
| useMoveHoverToCurrentCell | OK |
| useTriggerActionMenuDropdown | Ok |
| RecordTableBodyDragDropContextProvider | Ok |
| RecordTableHeaderCell | Ok |
| useSetCurrentRowSelected | Ok |
| useRecordTitleCell | Ok |
| SettingsObjectFieldActiveActionDropdown | Ok |
| SettingsObjectFieldInactiveActionDropdown | Ok |
| SettingsObjectFieldItemTableRow | Ok |
| SettingsObjectInactiveMenuDropDown | Ok |
| SettingsRoleEditEffect | Ok |
| SettingsRolesQueryEffect | Ok |
| Dropdown | Ok |
| useSelectableList | Ok |
| useSelectableListHotKeys | Ok |
| useSelectableListListenToEnterHotkeyOnItem | Ok |
| useNavigationSection | Ok |
| useCreateViewFromCurrentState | Ok |
| useDeleteViewFromCurrentState | Ok |
| useUpdateViewFromCurrentState | Ok |
| ViewPickerFavoriteFoldersDropdown | Ok |
| useCreateViewFromCurrentView | Ok |
| ViewBarDetails | Ok |
| WorkflowRunVisualizer | Ok |
| useHandleWorkflowRunDiagramCanvasInit | Ok |
| WorkflowDiagramCanvasBase | Ok |
| WorkflowRunVisualizerEffect | Ok |
| useRemoveStepFilter | Ok |
| useRemoveStepFilterGroup | Ok |
| useUpsertStepFilterSettings | Ok |
| WorkflowFindRecordsFilters | Ok |
| SettingsObjects | Ok |
This commit is contained in:
Lucas Bordeau
2025-07-29 11:52:24 +02:00
committed by GitHub
parent bf8beb5735
commit d61eb1a951
140 changed files with 362 additions and 1367 deletions
@@ -30,7 +30,7 @@ import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRec
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { useRecordShowContainerData } from '@/object-record/record-show/hooks/useRecordShowContainerData';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
@@ -379,7 +379,7 @@ export const ActivityRichTextEditor = ({
({ snapshot }) =>
() => {
const isRecordTitleCellOpen = snapshot
.getLoadable(isInlineCellInEditModeScopedState(recordTitleCellId))
.getLoadable(isInlineCellInEditModeFamilyState(recordTitleCellId))
.getValue();
if (isRecordTitleCellOpen) {
@@ -405,7 +405,7 @@ export const ActivityRichTextEditor = ({
({ snapshot }) =>
() => {
const isRecordTitleCellOpen = snapshot
.getLoadable(isInlineCellInEditModeScopedState(recordTitleCellId))
.getLoadable(isInlineCellInEditModeFamilyState(recordTitleCellId))
.getValue();
if (isRecordTitleCellOpen) {
@@ -16,16 +16,16 @@ type AttachmentDropdownProps = {
onDownload: () => void;
onDelete: () => void;
onRename: () => void;
scopeKey: string;
attachmentId: string;
};
export const AttachmentDropdown = ({
onDownload,
onDelete,
onRename,
scopeKey,
attachmentId,
}: AttachmentDropdownProps) => {
const dropdownId = `${scopeKey}-settings-field-active-action-dropdown`;
const dropdownId = `${attachmentId}-attachment-dropdown`;
const { closeDropdown } = useCloseDropdown();
@@ -199,7 +199,7 @@ export const AttachmentRow = ({
</StyledCalendarIconContainer>
{formatToHumanReadableDate(attachment.createdAt)}
<AttachmentDropdown
scopeKey={attachment.id}
attachmentId={attachment.id}
onDelete={handleDelete}
onDownload={handleDownload}
onRename={handleRename}
@@ -8,7 +8,7 @@ import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTa
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
@@ -114,9 +114,11 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>
<MockedProvider cache={cache}>
<JestObjectMetadataItemSetter>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="snack-bar-manager">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'snack-bar-manager' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</JestObjectMetadataItemSetter>
</MockedProvider>
</RecoilRoot>
@@ -20,7 +20,7 @@ export const ObjectTasks = ({ targetableObject }: ObjectTasksProps) => {
return (
<StyledContainer>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: 'entity-tasks-filter-scope' }}
value={{ instanceId: 'entity-tasks-filter-instance' }}
>
<TaskGroups targetableObject={targetableObject} />
</ObjectFilterDropdownComponentInstanceContext.Provider>
@@ -4,7 +4,6 @@ import { TaskGroups } from '@/activities/tasks/components/TaskGroups';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { TabListComponentInstanceContext } from '@/ui/layout/tab-list/states/contexts/TabListComponentInstanceContext';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
@@ -18,17 +17,16 @@ const meta: Meta<typeof TaskGroups> = {
decorators: [
(Story) => (
<TabListComponentInstanceContext.Provider
value={{ instanceId: 'entity-tasks-filter-scope' }}
value={{ instanceId: 'entity-tasks-filter-instance' }}
>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: 'entity-tasks-filter-scope' }}
value={{ instanceId: 'entity-tasks-filter-instance' }}
>
<Story />
</ObjectFilterDropdownComponentInstanceContext.Provider>
</TabListComponentInstanceContext.Provider>
),
ComponentWithRouterDecorator,
ComponentWithRecoilScopeDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
I18nFrontDecorator,
@@ -47,7 +47,7 @@ jest.mock('@/activities/hooks/useActivities', () => ({
const Wrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>
<ObjectFilterDropdownComponentInstanceContext.Provider
value={{ instanceId: 'entity-tasks-filter-scope' }}
value={{ instanceId: 'entity-tasks-filter-instance' }}
>
{children}
</ObjectFilterDropdownComponentInstanceContext.Provider>
@@ -4,7 +4,7 @@ import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
import { MemoryRouter, useLocation } from 'react-router-dom';
import { RecoilRoot } from 'recoil';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { useApolloFactory } from '../useApolloFactory';
enableFetchMocks();
@@ -26,9 +26,11 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
initialEntries={['/welcome', '/verify', '/opportunities']}
initialIndex={2}
>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="test-instance-id">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'test-instance-id' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</MemoryRouter>
</RecoilRoot>
);
@@ -4,7 +4,7 @@ import { RecoilDebugObserverEffect } from '@/debug/components/RecoilDebugObserve
import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary';
import { AppRootErrorFallback } from '@/error-handler/components/AppRootErrorFallback';
import { ExceptionHandlerProvider } from '@/error-handler/components/ExceptionHandlerProvider';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
import { i18n } from '@lingui/core';
import { I18nProvider } from '@lingui/react';
@@ -25,7 +25,9 @@ export const App = () => {
<I18nProvider i18n={i18n}>
<RecoilDebugObserverEffect />
<ApolloDevLogEffect />
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="snack-bar-manager">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'snack-bar-manager' }}
>
<IconsProvider>
<ExceptionHandlerProvider>
<HelmetProvider>
@@ -37,7 +39,7 @@ export const App = () => {
</HelmetProvider>
</ExceptionHandlerProvider>
</IconsProvider>
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</I18nProvider>
</AppErrorBoundary>
</RecoilRoot>
@@ -15,7 +15,7 @@ import { ObjectMetadataItemsLoadEffect } from '@/object-metadata/components/Obje
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
import { PrefetchDataProvider } from '@/prefetch/components/PrefetchDataProvider';
import { DialogManager } from '@/ui/feedback/dialog-manager/components/DialogManager';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { SnackBarProvider } from '@/ui/feedback/snack-bar-manager/components/SnackBarProvider';
import { BaseThemeProvider } from '@/ui/theme/components/BaseThemeProvider';
import { UserThemeProviderEffect } from '@/ui/theme/components/UserThemeProviderEffect';
@@ -51,7 +51,9 @@ export const AppRouterProviders = () => {
<UserThemeProviderEffect />
<SnackBarProvider>
<ErrorMessageEffect />
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<DialogManager>
<StrictMode>
<PromiseRejectionEffect />
@@ -61,7 +63,7 @@ export const AppRouterProviders = () => {
<Outlet />
</StrictMode>
</DialogManager>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
</SnackBarProvider>
<MainContextStoreProvider />
</PrefetchDataProvider>
@@ -2,7 +2,7 @@ import { useAuth } from '@/auth/hooks/useAuth';
import { billingState } from '@/client-config/states/billingState';
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
import { supportChatState } from '@/client-config/states/supportChatState';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
import { useApolloClient } from '@apollo/client';
import { MockedProvider } from '@apollo/client/testing';
@@ -12,6 +12,7 @@ import { MemoryRouter } from 'react-router-dom';
import { RecoilRoot, useRecoilValue } from 'recoil';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { renderHook } from '@testing-library/react';
import { iconsState } from 'twenty-ui/display';
import { SupportDriver } from '~/generated/graphql';
@@ -71,9 +72,11 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
<MockedProvider mocks={Object.values(mocks)} addTypename={false}>
<RecoilRoot>
<MemoryRouter>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="test-scope-id">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'test-instance-id' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</MemoryRouter>
</RecoilRoot>
</MockedProvider>
@@ -15,7 +15,8 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useRunWorkflowRunOpeningInCommandMenuSideEffects } from '@/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects';
import { useTheme } from '@emotion/react';
import { t } from '@lingui/core/macro';
@@ -1,20 +0,0 @@
import { FavoriteFolderPickerInstanceContext } from '@/favorites/favorite-folder-picker/states/context/FavoriteFolderPickerInstanceContext';
import { ReactNode } from 'react';
type FavoriteFolderPickerComponentInstanceContextProps = {
children: ReactNode;
favoriteFoldersScopeId: string;
};
export const FavoriteFolderPickerComponentInstanceContext = ({
children,
favoriteFoldersScopeId,
}: FavoriteFolderPickerComponentInstanceContextProps) => {
return (
<FavoriteFolderPickerInstanceContext.Provider
value={{ instanceId: favoriteFoldersScopeId }}
>
{children}
</FavoriteFolderPickerInstanceContext.Provider>
);
};
@@ -4,8 +4,8 @@ import { ReactNode } from 'react';
import { RecoilRoot } from 'recoil';
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import {
query,
responseData,
@@ -27,9 +27,11 @@ const mocks = [
const Wrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>
<MockedProvider mocks={mocks} addTypename={false}>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="snack-bar-manager">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'snack-bar-manager' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</MockedProvider>
</RecoilRoot>
);
@@ -1,16 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
// TODO: refactor with scoped state later
export const useUpsertRecordFromState = () =>
useRecoilCallback(
({ set }) =>
<T extends ObjectRecord>(record: T) =>
set(recordStoreFamilyState(record.id), (previousRecord) =>
isDeeplyEqual(previousRecord, record) ? previousRecord : record,
),
[],
);
@@ -24,7 +24,7 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const instanceId = 'entity-options-scope';
const instanceId = 'entity-options-instance';
const meta: Meta<typeof ObjectOptionsDropdownContent> = {
title:
@@ -16,7 +16,6 @@ import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useR
import { RecordBoardDeactivateBoardCardEffect } from '@/object-record/record-board/record-board-card/components/RecordBoardDeactivateBoardCardEffect';
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
import { RecordBoardColumn } from '@/object-record/record-board/record-board-column/components/RecordBoardColumn';
import { RecordBoardScope } from '@/object-record/record-board/scopes/RecordBoardScope';
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
import { getDraggedRecordPosition } from '@/object-record/record-board/utils/getDraggedRecordPosition';
import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState';
@@ -209,51 +208,43 @@ export const RecordBoard = () => {
// }
return (
<RecordBoardScope
recordBoardScopeId={recordBoardId}
onColumnsChange={() => {}}
onFieldsChange={() => {}}
<RecordBoardComponentInstanceContext.Provider
value={{ instanceId: recordBoardId }}
>
<RecordBoardComponentInstanceContext.Provider
value={{ instanceId: recordBoardId }}
<ScrollWrapper
componentInstanceId={`scroll-wrapper-record-board-${recordBoardId}`}
>
<ScrollWrapper
componentInstanceId={`scroll-wrapper-record-board-${recordBoardId}`}
>
<RecordBoardStickyHeaderEffect />
<RecordBoardScrollToFocusedCardEffect />
<RecordBoardDeactivateBoardCardEffect />
<StyledContainerContainer>
<RecordBoardHeader />
<StyledBoardContentContainer>
<StyledContainer ref={boardRef}>
<DragDropContext onDragEnd={handleDragEnd}>
<StyledColumnContainer>
{visibleRecordGroupIds.map((recordGroupId, index) => (
<RecordBoardColumn
key={recordGroupId}
recordBoardColumnId={recordGroupId}
recordBoardColumnIndex={index}
/>
))}
</StyledColumnContainer>
</DragDropContext>
<RecordBoardStickyHeaderEffect />
<RecordBoardScrollToFocusedCardEffect />
<RecordBoardDeactivateBoardCardEffect />
<StyledContainerContainer>
<RecordBoardHeader />
<StyledBoardContentContainer>
<StyledContainer ref={boardRef}>
<DragDropContext onDragEnd={handleDragEnd}>
<StyledColumnContainer>
{visibleRecordGroupIds.map((recordGroupId, index) => (
<RecordBoardColumn
key={recordGroupId}
recordBoardColumnId={recordGroupId}
recordBoardColumnIndex={index}
/>
))}
</StyledColumnContainer>
</DragDropContext>
<DragSelect
selectableItemsContainerRef={boardRef}
onDragSelectionEnd={handleDragSelectionEnd}
onDragSelectionChange={setRecordAsSelected}
onDragSelectionStart={handleDragSelectionStart}
scrollWrapperComponentInstanceId={`scroll-wrapper-record-board-${recordBoardId}`}
selectionBoundaryClass={
RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS
}
/>
</StyledContainer>
</StyledBoardContentContainer>
</StyledContainerContainer>
</ScrollWrapper>
</RecordBoardComponentInstanceContext.Provider>
</RecordBoardScope>
<DragSelect
selectableItemsContainerRef={boardRef}
onDragSelectionEnd={handleDragSelectionEnd}
onDragSelectionChange={setRecordAsSelected}
onDragSelectionStart={handleDragSelectionStart}
scrollWrapperComponentInstanceId={`scroll-wrapper-record-board-${recordBoardId}`}
selectionBoundaryClass={RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS}
/>
</StyledContainer>
</StyledBoardContentContainer>
</StyledContainerContainer>
</ScrollWrapper>
</RecordBoardComponentInstanceContext.Provider>
);
};
@@ -1,24 +1,16 @@
import { useEffect } from 'react';
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
import { focusedRecordBoardCardIndexesComponentState } from '@/object-record/record-board/states/focusedRecordBoardCardIndexesComponentState';
import { isRecordBoardCardFocusActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCardFocusActiveComponentState';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const RecordBoardScrollToFocusedCardEffect = () => {
const recordBoardId = useAvailableScopeIdOrThrow(
RecordBoardScopeInternalContext,
);
const focusedCardIndexes = useRecoilComponentValueV2(
focusedRecordBoardCardIndexesComponentState,
recordBoardId,
);
const isFocusActive = useRecoilComponentValueV2(
isRecordBoardCardFocusActiveComponentState,
recordBoardId,
);
useEffect(() => {
@@ -4,8 +4,8 @@ import { useRecordBoardSelection } from '@/object-record/record-board/hooks/useR
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
import { allCardsSelectedStatusComponentSelector } from '@/object-record/record-board/states/selectors/allCardsSelectedStatusComponentSelector';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export const useSelectAllCards = (recordBoardId?: string) => {
const allCardsSelectedStatusSelector = useRecoilComponentCallbackStateV2(
@@ -2,7 +2,6 @@ import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-me
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
import { RecordBoardCardContext } from '@/object-record/record-board/record-board-card/contexts/RecordBoardCardContext';
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
import { isRecordBoardCardActiveComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardActiveComponentFamilyState';
import { isRecordBoardCardFocusedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardFocusedComponentFamilyState';
import { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
@@ -14,10 +13,11 @@ import { useFocusedRecordBoardCard } from '@/object-record/record-board/hooks/us
import { RecordBoardCardBody } from '@/object-record/record-board/record-board-card/components/RecordBoardCardBody';
import { RecordBoardCardHeader } from '@/object-record/record-board/record-board-card/components/RecordBoardCardHeader';
import { RECORD_BOARD_CARD_CLICK_OUTSIDE_ID } from '@/object-record/record-board/record-board-card/constants/RecordBoardCardClickOutsideId';
import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext';
import { useOpenRecordFromIndexView } from '@/object-record/record-index/hooks/useOpenRecordFromIndexView';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@@ -122,8 +122,8 @@ export const RecordBoardCard = () => {
},
);
const recordBoardId = useAvailableScopeIdOrThrow(
RecordBoardScopeInternalContext,
const recordBoardId = useAvailableComponentInstanceIdOrThrow(
RecordBoardComponentInstanceContext,
);
const actionMenuId = getActionMenuIdFromRecordIndexId(recordBoardId);
@@ -1,33 +0,0 @@
import { ReactNode } from 'react';
import { RecordBoardScopeInternalContext } from '@/object-record/record-board/scopes/scope-internal-context/RecordBoardScopeInternalContext';
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
type RecordBoardScopeProps = {
children: ReactNode;
recordBoardScopeId: string;
onFieldsChange: (fields: FieldDefinition<FieldMetadata>[]) => void;
onColumnsChange: (column: RecordGroupDefinition[]) => void;
};
/** @deprecated */
export const RecordBoardScope = ({
children,
recordBoardScopeId,
onColumnsChange,
onFieldsChange,
}: RecordBoardScopeProps) => {
return (
<RecordBoardScopeInternalContext.Provider
value={{
scopeId: recordBoardScopeId,
onColumnsChange,
onFieldsChange,
}}
>
{children}
</RecordBoardScopeInternalContext.Provider>
);
};
@@ -1,13 +0,0 @@
import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
type RecordBoardScopeInternalContextProps = RecoilComponentStateKey & {
onFieldsChange: (fields: FieldDefinition<FieldMetadata>[]) => void;
onColumnsChange: (column: RecordGroupDefinition[]) => void;
};
export const RecordBoardScopeInternalContext =
createScopeInternalContext<RecordBoardScopeInternalContextProps>();
@@ -6,7 +6,6 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { RelationFromManyFieldInput } from '@/object-record/record-field/meta-types/input/components/RelationFromManyFieldInput';
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
@@ -127,6 +126,4 @@ export default meta;
type Story = StoryObj<typeof RelationManyFieldInputWithContext>;
export const Default: Story = {
decorators: [ComponentWithRecoilScopeDecorator],
};
export const Default: Story = {};
@@ -5,7 +5,6 @@ import { useSetRecoilState } from 'recoil';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
@@ -150,12 +149,9 @@ export default meta;
type Story = StoryObj<typeof RelationToOneFieldInputWithContext>;
export const Default: Story = {
decorators: [ComponentWithRecoilScopeDecorator],
};
export const Default: Story = {};
export const Submit: Story = {
decorators: [ComponentWithRecoilScopeDecorator],
play: async () => {
const canvas = within(getCanvasElementForDropdownTesting());
@@ -174,7 +170,6 @@ export const Submit: Story = {
};
export const Cancel: Story = {
decorators: [ComponentWithRecoilScopeDecorator],
play: async () => {
const canvas = within(getCanvasElementForDropdownTesting());
@@ -14,7 +14,7 @@ import { useIsFieldInputOnly } from '@/object-record/record-field/hooks/useIsFie
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/states/contexts/RecordFieldComponentInstanceContext';
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
@@ -85,7 +85,7 @@ export const RecordInlineCell = ({
);
const setIsInlineCellInEditMode = useSetRecoilState(
isInlineCellInEditModeScopedState(recordFieldComponentInstanceId),
isInlineCellInEditModeFamilyState(recordFieldComponentInstanceId),
);
const closeInlineCell = useCallback(() => {
@@ -10,7 +10,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { isInlineCellInEditModeScopedState } from '../states/isInlineCellInEditModeScopedState';
import { isInlineCellInEditModeFamilyState } from '../states/isInlineCellInEditModeFamilyState';
export const useInlineCell = (
recordFieldComponentInstanceIdFromProps?: string,
@@ -23,7 +23,7 @@ export const useInlineCell = (
);
const [isInlineCellInEditMode, setIsInlineCellInEditMode] = useRecoilState(
isInlineCellInEditModeScopedState(recordFieldComponentInstanceId),
isInlineCellInEditModeFamilyState(recordFieldComponentInstanceId),
);
const { onOpenEditMode, onCloseEditMode } = useRecordInlineCellContext();
@@ -1,6 +1,6 @@
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
export const isInlineCellInEditModeScopedState = createFamilyState<
export const isInlineCellInEditModeFamilyState = createFamilyState<
boolean,
string
>({
@@ -2,7 +2,6 @@ import { Meta, StoryObj } from '@storybook/react';
import { expect, userEvent, within } from '@storybook/test';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
@@ -11,8 +10,8 @@ import { sleep } from '~/utils/sleep';
import { SingleRecordPicker } from '@/object-record/record-picker/single-record-picker/components/SingleRecordPicker';
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
import { ComponentDecorator } from 'twenty-ui/testing';
import { IconUserCircle } from 'twenty-ui/display';
import { ComponentDecorator } from 'twenty-ui/testing';
const records = allMockPersonRecords.map<SingleRecordPickerRecord>(
(person) => ({
@@ -29,7 +28,6 @@ const meta: Meta<typeof SingleRecordPicker> = {
component: SingleRecordPicker,
decorators: [
ComponentDecorator,
ComponentWithRecoilScopeDecorator,
ObjectMetadataItemsDecorator,
SnackBarDecorator,
],
@@ -35,7 +35,6 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
@@ -159,12 +158,12 @@ export const RecordDetailRelationRecordsListItem = ({
)
.sort();
const dropdownScopeId = `record-field-card-menu-${relationFieldMetadataId}-${relationRecord.id}`;
const dropdownInstanceId = `record-field-card-menu-${relationFieldMetadataId}-${relationRecord.id}`;
const { closeDropdown } = useCloseDropdown();
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownScopeId,
dropdownInstanceId,
);
const dropdownId = getRecordFieldCardRelationPickerDropdownId({
@@ -177,7 +176,7 @@ export const RecordDetailRelationRecordsListItem = ({
);
const handleDetach = () => {
closeDropdown(dropdownScopeId);
closeDropdown(dropdownInstanceId);
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
({ id }) => id === relationFieldMetadataId,
@@ -202,7 +201,7 @@ export const RecordDetailRelationRecordsListItem = ({
};
const handleDelete = async () => {
closeDropdown(dropdownScopeId);
closeDropdown(dropdownInstanceId);
openModal(getDeleteRelationModalId(relationRecord.id));
};
@@ -262,39 +261,37 @@ export const RecordDetailRelationRecordsListItem = ({
/>
</StyledClickableZone>
{!isFieldReadOnly && (
<DropdownScope dropdownScopeId={dropdownScopeId}>
<Dropdown
dropdownId={dropdownScopeId}
dropdownPlacement="right-start"
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconDotsVertical}
accent="tertiary"
/>
}
dropdownComponents={
<DropdownContent>
<DropdownMenuItemsContainer>
<MenuItem
LeftIcon={IconUnlink}
text="Detach"
onClick={handleDetach}
/>
{!isAccountOwnerRelation &&
relationObjectPermissions.canSoftDeleteObjectRecords && (
<MenuItem
LeftIcon={IconTrash}
text="Delete"
accent="danger"
onClick={handleDelete}
/>
)}
</DropdownMenuItemsContainer>
</DropdownContent>
}
/>
</DropdownScope>
<Dropdown
dropdownId={dropdownInstanceId}
dropdownPlacement="right-start"
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconDotsVertical}
accent="tertiary"
/>
}
dropdownComponents={
<DropdownContent>
<DropdownMenuItemsContainer>
<MenuItem
LeftIcon={IconUnlink}
text="Detach"
onClick={handleDetach}
/>
{!isAccountOwnerRelation &&
relationObjectPermissions.canSoftDeleteObjectRecords && (
<MenuItem
LeftIcon={IconTrash}
text="Delete"
accent="danger"
onClick={handleDelete}
/>
)}
</DropdownMenuItemsContainer>
</DropdownContent>
}
/>
)}
</StyledListItem>
<AnimatedEaseInOut isOpen={isExpanded}>
@@ -17,7 +17,6 @@ import { recordStoreFamilySelector } from '@/object-record/record-store/states/s
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
@@ -131,39 +130,37 @@ export const RecordDetailRelationSectionDropdownToMany = () => {
};
return (
<DropdownScope dropdownScopeId={dropdownId}>
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="left-start"
onClose={handleCloseRelationPickerDropdown}
onOpen={handleOpenRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<MultipleRecordPicker
focusId={dropdownId}
componentInstanceId={dropdownId}
onCreate={handleCreateNew}
onChange={updateRelation}
onSubmit={() => {
closeDropdown(dropdownId);
}}
onClickOutside={() => {
closeDropdown(dropdownId);
}}
layoutDirection={
dropdownPlacement?.includes('end')
? 'search-bar-on-bottom'
: 'search-bar-on-top'
}
/>
}
/>
</DropdownScope>
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="left-start"
onClose={handleCloseRelationPickerDropdown}
onOpen={handleOpenRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<MultipleRecordPicker
focusId={dropdownId}
componentInstanceId={dropdownId}
onCreate={handleCreateNew}
onChange={updateRelation}
onSubmit={() => {
closeDropdown(dropdownId);
}}
onClickOutside={() => {
closeDropdown(dropdownId);
}}
layoutDirection={
dropdownPlacement?.includes('end')
? 'search-bar-on-bottom'
: 'search-bar-on-top'
}
/>
}
/>
);
};
@@ -17,7 +17,6 @@ import { recordStoreFamilySelector } from '@/object-record/record-store/states/s
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
@@ -117,37 +116,35 @@ export const RecordDetailRelationSectionDropdownToOne = () => {
CoreObjectNameSingular.WorkspaceMember;
return (
<DropdownScope dropdownScopeId={dropdownId}>
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="left-start"
onClose={handleCloseRelationPickerDropdown}
onOpen={handleOpenRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPencil}
accent="tertiary"
/>
}
dropdownComponents={
<SingleRecordPicker
focusId={dropdownId}
componentInstanceId={dropdownId}
EmptyIcon={IconForbid}
onRecordSelected={handleRelationPickerEntitySelected}
objectNameSingular={relationObjectMetadataNameSingular}
recordPickerInstanceId={dropdownId}
onCancel={() => closeDropdown(dropdownId)}
onCreate={shouldAllowCreateNew ? handleCreateNew : undefined}
layoutDirection={
dropdownPlacement?.includes('end')
? 'search-bar-on-bottom'
: 'search-bar-on-top'
}
/>
}
/>
</DropdownScope>
<Dropdown
dropdownId={dropdownId}
dropdownPlacement="left-start"
onClose={handleCloseRelationPickerDropdown}
onOpen={handleOpenRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPencil}
accent="tertiary"
/>
}
dropdownComponents={
<SingleRecordPicker
focusId={dropdownId}
componentInstanceId={dropdownId}
EmptyIcon={IconForbid}
onRecordSelected={handleRelationPickerEntitySelected}
objectNameSingular={relationObjectMetadataNameSingular}
recordPickerInstanceId={dropdownId}
onCancel={() => closeDropdown(dropdownId)}
onCreate={shouldAllowCreateNew ? handleCreateNew : undefined}
layoutDirection={
dropdownPlacement?.includes('end')
? 'search-bar-on-bottom'
: 'search-bar-on-top'
}
/>
}
/>
);
};
@@ -3,8 +3,8 @@ import { useRecoilCallback } from 'recoil';
import { useMoveHoverToCurrentCell } from '@/object-record/record-table/record-table-cell/hooks/useMoveHoverToCurrentCell';
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export type HandleContainerMouseEnterArgs = {
cellPosition: TableCellPosition;
@@ -7,9 +7,9 @@ import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-tab
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { lastSelectedRowIndexComponentState } from '../../record-table-row/states/lastSelectedRowIndexComponentState';
export const useResetTableRowSelection = (recordTableId?: string) => {
@@ -4,8 +4,8 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record
import { useResetTableRowSelection } from '@/object-record/record-table/hooks/internal/useResetTableRowSelection';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { allRowsSelectedStatusComponentSelector } from '@/object-record/record-table/states/selectors/allRowsSelectedStatusComponentSelector';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export const useSelectAllRows = (recordTableId?: string) => {
const allRowsSelectedStatusSelector = useRecoilComponentCallbackStateV2(
@@ -10,10 +10,10 @@ import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-tab
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilComponentFamilyCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDefined } from 'twenty-shared/utils';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
@@ -2,7 +2,7 @@ import { useRecoilCallback } from 'recoil';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useSetHasUserSelectedAllRows } from '@/object-record/record-table/hooks/internal/useSetAllRowSelectedState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
import { ColumnDefinition } from '../types/ColumnDefinition';
@@ -1,7 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useFocusRecordTableCell } from '@/object-record/record-table/record-table-cell/hooks/useFocusRecordTableCell';
@@ -4,8 +4,8 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record
import { useFocusedRecordTableRow } from '@/object-record/record-table/hooks/useFocusedRecordTableRow';
import { focusedRecordTableRowIndexComponentState } from '@/object-record/record-table/states/focusedRecordTableRowIndexComponentState';
import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDefined } from 'twenty-shared/utils';
export const useRecordTableMoveFocusedRow = (recordTableId?: string) => {
@@ -10,9 +10,9 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/st
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDefined } from 'twenty-shared/utils';
export const RecordTableBodyDragDropContextProvider = ({
@@ -22,7 +22,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const onColumnsChange = jest.fn();
const recordTableId = 'scopeId';
const recordTableId = 'record-table-id';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot
@@ -22,7 +22,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
const onColumnsChange = jest.fn();
const recordTableId = 'scopeId';
const recordTableId = 'record-table-id';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot
@@ -1,7 +1,7 @@
import { useRecoilCallback } from 'recoil';
import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
@@ -6,9 +6,9 @@ import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/get
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
export const useTriggerActionMenuDropdown = ({
recordTableId,
@@ -17,12 +17,12 @@ import { tableColumnsComponentState } from '@/object-record/record-table/states/
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer';
import { PointerEventListener } from '@/ui/utilities/pointer-event/types/PointerEventListener';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { IconPlus } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
@@ -4,8 +4,8 @@ import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState';
import { lastSelectedRowIndexComponentState } from '@/object-record/record-table/record-table-row/states/lastSelectedRowIndexComponentState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDefined } from 'twenty-shared/utils';
export const useSetCurrentRowSelected = () => {
@@ -4,7 +4,6 @@ import { ComponentStateKeyV2 } from '@/ui/utilities/state/component-state/types/
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
import { ColumnDefinition } from '../../types/ColumnDefinition';
// TODO: separate scope contexts from event contexts
type RecordTableComponentInstanceContextProps = ComponentStateKeyV2 & {
onColumnsChange: (columns: ColumnDefinition<FieldMetadata>[]) => void;
};
@@ -1,7 +1,7 @@
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
import { useInitDraftValueV2 } from '@/object-record/record-field/hooks/useInitDraftValueV2';
import { isInlineCellInEditModeScopedState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeScopedState';
import { isInlineCellInEditModeFamilyState } from '@/object-record/record-inline-cell/states/isInlineCellInEditModeFamilyState';
import { RecordTitleCellContainerType } from '@/object-record/record-title-cell/types/RecordTitleCellContainerType';
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
@@ -32,7 +32,7 @@ export const useRecordTitleCell = () => {
containerType: RecordTitleCellContainerType;
}) => {
set(
isInlineCellInEditModeScopedState(
isInlineCellInEditModeFamilyState(
getRecordFieldInputInstanceId({
recordId,
fieldName,
@@ -93,7 +93,7 @@ export const useRecordTitleCell = () => {
fieldName,
prefix: containerType,
});
set(isInlineCellInEditModeScopedState(recordTitleCellId), true);
set(isInlineCellInEditModeFamilyState(recordTitleCellId), true);
const fieldDefinitions = objectMetadataItem.fields.map(
(fieldMetadataItem, index) =>
@@ -5,9 +5,9 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { MultipleRecordPickerRecords } from '@/object-record/record-picker/multiple-record-picker/types/MultipleRecordPickerRecords';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import {
query,
@@ -55,9 +55,11 @@ const mocks = [
const Wrapper = ({ children }: { children: ReactNode }) => (
<RecoilRoot>
<MockedProvider mocks={mocks} addTypename={false}>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="snack-bar-manager">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'snack-bar-manager' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</MockedProvider>
</RecoilRoot>
);
@@ -19,7 +19,7 @@ type SettingsObjectFieldActiveActionDropdownProps = {
onDeactivate?: () => void;
onEdit: () => void;
onSetAsLabelIdentifier?: () => void;
scopeKey: string;
fieldMetadataItemId: string;
};
export const SettingsObjectFieldActiveActionDropdown = ({
@@ -27,9 +27,9 @@ export const SettingsObjectFieldActiveActionDropdown = ({
onDeactivate,
onEdit,
onSetAsLabelIdentifier,
scopeKey,
fieldMetadataItemId,
}: SettingsObjectFieldActiveActionDropdownProps) => {
const dropdownId = `${scopeKey}-settings-field-active-action-dropdown`;
const dropdownId = `${fieldMetadataItemId}-settings-field-active-action-dropdown`;
const { closeDropdown } = useCloseDropdown();
@@ -21,17 +21,17 @@ type SettingsObjectFieldInactiveActionDropdownProps = {
onActivate: () => void;
onEdit: () => void;
onDelete: () => void;
scopeKey: string;
fieldMetadataItemId: string;
};
export const SettingsObjectFieldInactiveActionDropdown = ({
onActivate,
scopeKey,
fieldMetadataItemId,
onDelete,
onEdit,
isCustomField,
}: SettingsObjectFieldInactiveActionDropdownProps) => {
const dropdownId = `${scopeKey}-settings-field-disabled-action-dropdown`;
const dropdownId = `${fieldMetadataItemId}-settings-field-disabled-action-dropdown`;
const { closeDropdown } = useCloseDropdown();
@@ -270,7 +270,7 @@ export const SettingsObjectFieldItemTableRow = ({
mode === 'view' ? (
<SettingsObjectFieldActiveActionDropdown
isCustomField={fieldMetadataItem.isCustom === true}
scopeKey={fieldMetadataItem.id}
fieldMetadataItemId={fieldMetadataItem.id}
onEdit={() =>
navigate(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
@@ -300,7 +300,7 @@ export const SettingsObjectFieldItemTableRow = ({
) : mode === 'view' ? (
<SettingsObjectFieldInactiveActionDropdown
isCustomField={fieldMetadataItem.isCustom === true}
scopeKey={fieldMetadataItem.id}
fieldMetadataItemId={fieldMetadataItem.id}
onEdit={() =>
navigate(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
@@ -11,16 +11,16 @@ type SettingsObjectInactiveMenuDropDownProps = {
isCustomObject: boolean;
onActivate: () => void;
onDelete: () => void;
scopeKey: string;
objectMetadataItemNamePlural: string;
};
export const SettingsObjectInactiveMenuDropDown = ({
onActivate,
scopeKey,
objectMetadataItemNamePlural,
onDelete,
isCustomObject,
}: SettingsObjectInactiveMenuDropDownProps) => {
const dropdownId = `${scopeKey}-settings-object-inactive-menu-dropdown`;
const dropdownId = `${objectMetadataItemNamePlural}-settings-object-inactive-menu-dropdown`;
const { closeDropdown } = useCloseDropdown();
@@ -1,8 +1,8 @@
import { Decorator, Meta, StoryObj } from '@storybook/react';
import { expect, fn, userEvent, within } from '@storybook/test';
import { SettingsObjectInactiveMenuDropDown } from '../SettingsObjectInactiveMenuDropDown';
import { ComponentDecorator } from 'twenty-ui/testing';
import { SettingsObjectInactiveMenuDropDown } from '../SettingsObjectInactiveMenuDropDown';
const handleActivateMockFunction = fn();
const handleDeleteMockFunction = fn();
@@ -19,7 +19,7 @@ const meta: Meta<typeof SettingsObjectInactiveMenuDropDown> = {
title: 'Modules/Settings/DataModel/SettingsObjectInactiveMenuDropDown',
component: SettingsObjectInactiveMenuDropDown,
args: {
scopeKey: 'settings-object-inactive-menu-dropdown',
objectMetadataItemNamePlural: 'settings-object-inactive-menu-dropdown',
onActivate: handleActivateMockFunction,
onDelete: handleDeleteMockFunction,
},
@@ -14,7 +14,7 @@ import { currentUserState } from '@/auth/states/currentUserState';
import { billingState } from '@/client-config/states/billingState';
import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
const mockCurrentUser = {
id: 'fake-user-id',
@@ -45,9 +45,11 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
<MockedProvider>
<RecoilRoot initializeState={initializeState}>
<MemoryRouter>
<SnackBarComponentInstanceContextProvider snackBarComponentInstanceId="test-scope-id">
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: 'test-scope-id' }}
>
{children}
</SnackBarComponentInstanceContextProvider>
</SnackBarComponentInstanceContext.Provider>
</MemoryRouter>
</RecoilRoot>
</MockedProvider>
@@ -4,13 +4,12 @@ import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import {
ComponentDecorator,
ComponentWithRouterDecorator,
} from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
const PlaygroundApiKeySetterEffect = () => {
const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState);
@@ -29,7 +28,6 @@ const meta: Meta<typeof GraphQLPlayground> = {
ComponentDecorator,
I18nFrontDecorator,
ComponentWithRouterDecorator,
ComponentWithRecoilScopeDecorator,
],
parameters: {
docs: {
@@ -1,18 +1,12 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { PlaygroundSetupForm } from '../PlaygroundSetupForm';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
const meta: Meta<typeof PlaygroundSetupForm> = {
title: 'Modules/Settings/Playground/PlaygroundSetupForm',
component: PlaygroundSetupForm,
decorators: [
ComponentDecorator,
RouterDecorator,
I18nFrontDecorator,
ComponentWithRecoilScopeDecorator,
],
decorators: [ComponentDecorator, RouterDecorator, I18nFrontDecorator],
parameters: {
docs: {
description: {
@@ -2,13 +2,12 @@ import { playgroundApiKeyState } from '@/settings/playground/states/playgroundAp
import { PlaygroundSchemas } from '@/settings/playground/types/PlaygroundSchemas';
import { action } from '@storybook/addon-actions';
import { Meta, StoryObj } from '@storybook/react';
import { http, HttpResponse } from 'msw';
import { HttpResponse, http } from 'msw';
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { ComponentDecorator } from 'twenty-ui/testing';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { RestPlayground } from '../RestPlayground';
import { ComponentDecorator } from 'twenty-ui/testing';
const PlaygroundApiKeySetterEffect = () => {
const setPlaygroundApiKey = useSetRecoilState(playgroundApiKeyState);
@@ -88,11 +87,7 @@ const openApiSpec = {
const meta: Meta<typeof RestPlayground> = {
title: 'Modules/Settings/Playground/RestPlayground',
component: RestPlayground,
decorators: [
ComponentDecorator,
I18nFrontDecorator,
ComponentWithRecoilScopeDecorator,
],
decorators: [ComponentDecorator, I18nFrontDecorator],
parameters: {
docs: {
description: {
@@ -2,7 +2,7 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDr
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { settingsRoleIdsState } from '@/settings/roles/states/settingsRoleIdsState';
import { settingsRolesIsLoadingState } from '@/settings/roles/states/settingsRolesIsLoadingState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useEffect } from 'react';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@@ -2,8 +2,8 @@ import { SETTINGS_ROLE_DETAIL_TABS } from '@/settings/roles/role/constants/Setti
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { useEffect, useState } from 'react';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@@ -5,7 +5,7 @@ import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/comp
import { SpreadSheetImportModalWrapper } from '@/spreadsheet-import/components/SpreadSheetImportModalWrapper';
import { MatchColumnsStep } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
@@ -62,7 +62,9 @@ const mockData = [
];
export const Default = () => (
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<ReactSpreadsheetImportContextProvider values={mockRsiValues}>
<SpreadSheetImportModalWrapper
modalId="match-columns-step"
@@ -80,5 +82,5 @@ export const Default = () => (
/>
</SpreadSheetImportModalWrapper>
</ReactSpreadsheetImportContextProvider>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
);
@@ -8,7 +8,7 @@ import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/comp
import { SpreadSheetImportModalWrapper } from '@/spreadsheet-import/components/SpreadSheetImportModalWrapper';
import { SelectHeaderStep } from '@/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
import { RecoilRoot } from 'recoil';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
@@ -40,7 +40,9 @@ const meta: Meta<typeof SelectHeaderStep> = {
export default meta;
export const Default = () => (
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<ReactSpreadsheetImportContextProvider values={mockRsiValues}>
<SpreadSheetImportModalWrapper
modalId="select-header-step"
@@ -60,5 +62,5 @@ export const Default = () => (
/>
</SpreadSheetImportModalWrapper>
</ReactSpreadsheetImportContextProvider>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
);
@@ -5,7 +5,7 @@ import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/comp
import { SpreadSheetImportModalWrapper } from '@/spreadsheet-import/components/SpreadSheetImportModalWrapper';
import { SelectSheetStep } from '@/spreadsheet-import/steps/components/SelectSheetStep/SelectSheetStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
import { RecoilRoot } from 'recoil';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
@@ -40,7 +40,9 @@ export default meta;
const sheetNames = ['Sheet1', 'Sheet2', 'Sheet3'];
export const Default = () => (
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<ReactSpreadsheetImportContextProvider values={mockRsiValues}>
<SpreadSheetImportModalWrapper
modalId="select-sheet-step"
@@ -78,5 +80,5 @@ export const Default = () => (
/>
</SpreadSheetImportModalWrapper>
</ReactSpreadsheetImportContextProvider>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
);
@@ -1,6 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
import { stepBarInternalState } from '@/ui/navigation/step-bar/states/stepBarInternalState';
@@ -13,7 +12,6 @@ const meta: Meta<typeof SpreadsheetImportStepperContainer> = {
title: 'Modules/SpreadsheetImport/Steps',
component: SpreadsheetImportStepperContainer,
decorators: [
ComponentWithRecoilScopeDecorator,
SnackBarDecorator,
I18nFrontDecorator,
ObjectMetadataItemsDecorator,
@@ -5,7 +5,7 @@ import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/comp
import { SpreadSheetImportModalWrapper } from '@/spreadsheet-import/components/SpreadSheetImportModalWrapper';
import { UploadStep } from '@/spreadsheet-import/steps/components/UploadStep/UploadStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
import { RecoilRoot } from 'recoil';
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
@@ -44,7 +44,9 @@ const meta: Meta<typeof UploadStep> = {
export default meta;
export const Default = () => (
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<ReactSpreadsheetImportContextProvider values={mockRsiValues}>
<SpreadSheetImportModalWrapper modalId="upload-step" onClose={() => null}>
<UploadStep
@@ -57,5 +59,5 @@ export const Default = () => (
/>
</SpreadSheetImportModalWrapper>
</ReactSpreadsheetImportContextProvider>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
);
@@ -8,7 +8,7 @@ import {
import { ReactSpreadsheetImportContextProvider } from '@/spreadsheet-import/components/ReactSpreadsheetImportContextProvider';
import { SpreadSheetImportModalWrapper } from '@/spreadsheet-import/components/SpreadSheetImportModalWrapper';
import { ValidationStep } from '@/spreadsheet-import/steps/components/ValidationStep/ValidationStep';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { isModalOpenedComponentState } from '@/ui/layout/modal/states/isModalOpenedComponentState';
import { RecoilRoot } from 'recoil';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
@@ -43,7 +43,9 @@ export default meta;
const file = new File([''], 'file.csv');
export const Default = () => (
<DialogManagerScope dialogComponentInstanceId="dialog-manager">
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
<ReactSpreadsheetImportContextProvider values={mockRsiValues}>
<SpreadSheetImportModalWrapper
modalId="validation-step"
@@ -58,5 +60,5 @@ export const Default = () => (
/>
</SpreadSheetImportModalWrapper>
</ReactSpreadsheetImportContextProvider>
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
);
@@ -1,3 +0,0 @@
import { Context } from 'react';
export type RecoilScopeContext = Context<string | null>;
@@ -1 +0,0 @@
export const DIALOG_MANAGER_HOTKEY_SCOPE_MEMOIZE_KEY = 'dialog-manager';
@@ -2,8 +2,8 @@ import { act, renderHook } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { v4 as uuidv4 } from 'uuid';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogManager';
import { DialogManagerScope } from '@/ui/feedback/dialog-manager/scopes/DialogManagerScope';
import { dialogInternalComponentState } from '@/ui/feedback/dialog-manager/states/dialogInternalComponentState';
import { DialogOptions } from '@/ui/feedback/dialog-manager/types/DialogOptions';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@@ -13,12 +13,13 @@ jest.mock('uuid');
(uuidv4 as jest.Mock).mockReturnValue(mockedUuid);
const dialogManagerScopeId = 'dialog-manager';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<RecoilRoot>
<DialogManagerScope dialogComponentInstanceId={dialogManagerScopeId}>
<DialogComponentInstanceContext.Provider
value={{ instanceId: 'dialog-manager' }}
>
{children}
</DialogManagerScope>
</DialogComponentInstanceContext.Provider>
</RecoilRoot>
);
@@ -1,21 +0,0 @@
import { ReactNode } from 'react';
import { DialogComponentInstanceContext } from '@/ui/feedback/dialog-manager/contexts/DialogComponentInstanceContext';
type DialogManagerScopeProps = {
children: ReactNode;
dialogComponentInstanceId: string;
};
export const DialogManagerScope = ({
children,
dialogComponentInstanceId,
}: DialogManagerScopeProps) => {
return (
<DialogComponentInstanceContext.Provider
value={{ instanceId: dialogComponentInstanceId }}
>
{children}
</DialogComponentInstanceContext.Provider>
);
};
@@ -1,21 +0,0 @@
import { ReactNode } from 'react';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
type SnackBarComponentInstanceContextProviderProps = {
children: ReactNode;
snackBarComponentInstanceId: string;
};
export const SnackBarComponentInstanceContextProvider = ({
children,
snackBarComponentInstanceId,
}: SnackBarComponentInstanceContextProviderProps) => {
return (
<SnackBarComponentInstanceContext.Provider
value={{ instanceId: snackBarComponentInstanceId }}
>
{children}
</SnackBarComponentInstanceContext.Provider>
);
};
@@ -4,7 +4,6 @@ import { DROPDOWN_RESIZE_MIN_HEIGHT } from '@/ui/layout/dropdown/constants/Dropd
import { DROPDOWN_RESIZE_MIN_WIDTH } from '@/ui/layout/dropdown/constants/DropdownResizeMinWidth';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { dropdownMaxHeightComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxHeightComponentState';
import { dropdownMaxWidthComponentState } from '@/ui/layout/dropdown/states/internal/dropdownMaxWidthComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
@@ -174,43 +173,39 @@ export const Dropdown = ({
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
<DropdownScope dropdownScopeId={dropdownId}>
<>
{isDefined(clickableComponent) ? (
<StyledClickableComponent
ref={refs.setReference}
onClick={handleClickableComponentClick}
aria-controls={`${dropdownId}-options`}
aria-expanded={isDropdownOpen}
aria-haspopup={true}
role="button"
width={clickableComponentWidth}
>
{clickableComponent}
</StyledClickableComponent>
) : (
<StyledDropdownFallbackAnchor ref={refs.setReference} />
)}
{isDropdownOpen && (
<DropdownInternalContainer
floatingStyles={floatingStyles}
dropdownComponents={dropdownComponents}
dropdownId={dropdownId}
dropdownPlacement={placement}
floatingUiRefs={refs}
hotkey={hotkey}
onClickOutside={onClickOutside}
onHotkeyTriggered={onOpen}
excludedClickOutsideIds={excludedClickOutsideIds}
isDropdownInModal={isDropdownInModal}
/>
)}
<DropdownOnToggleEffect
onDropdownClose={onClose}
onDropdownOpen={onOpen}
/>
</>
</DropdownScope>
{isDefined(clickableComponent) ? (
<StyledClickableComponent
ref={refs.setReference}
onClick={handleClickableComponentClick}
aria-controls={`${dropdownId}-options`}
aria-expanded={isDropdownOpen}
aria-haspopup={true}
role="button"
width={clickableComponentWidth}
>
{clickableComponent}
</StyledClickableComponent>
) : (
<StyledDropdownFallbackAnchor ref={refs.setReference} />
)}
{isDropdownOpen && (
<DropdownInternalContainer
floatingStyles={floatingStyles}
dropdownComponents={dropdownComponents}
dropdownId={dropdownId}
dropdownPlacement={placement}
floatingUiRefs={refs}
hotkey={hotkey}
onClickOutside={onClickOutside}
onHotkeyTriggered={onOpen}
excludedClickOutsideIds={excludedClickOutsideIds}
isDropdownInModal={isDropdownInModal}
/>
)}
<DropdownOnToggleEffect
onDropdownClose={onClose}
onDropdownOpen={onOpen}
/>
</DropdownComponentInstanceContext.Provider>
);
};
@@ -1,19 +0,0 @@
import { ReactNode } from 'react';
import { DropdownScopeInternalContext } from './scope-internal-context/DropdownScopeInternalContext';
type DropdownScopeProps = {
children: ReactNode;
dropdownScopeId: string;
};
export const DropdownScope = ({
children,
dropdownScopeId,
}: DropdownScopeProps) => {
return (
<DropdownScopeInternalContext.Provider value={{ scopeId: dropdownScopeId }}>
{children}
</DropdownScopeInternalContext.Provider>
);
};
@@ -1,7 +0,0 @@
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
type DropdownScopeInternalContextProps = RecoilComponentStateKey;
export const DropdownScopeInternalContext =
createScopeInternalContext<DropdownScopeInternalContextProps>();
@@ -8,7 +8,7 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
const selectableListScopeId = 'testId';
const selectableListComponentInstanceId = 'testId';
const testArr = [['1'], ['2'], ['3']];
const emptyArr = [[]];
@@ -18,12 +18,12 @@ describe('useSelectableList', () => {
() => {
const setSelectableItemIds = useSetRecoilComponentStateV2(
selectableItemIdsComponentState,
selectableListScopeId,
selectableListComponentInstanceId,
);
const selectableItemIds = useRecoilComponentValueV2(
selectableItemIdsComponentState,
selectableListScopeId,
selectableListComponentInstanceId,
);
return {
@@ -45,18 +45,20 @@ describe('useSelectableList', () => {
expect(result.current.selectableItemIds).toEqual(testArr);
});
it('Should resetSelectItem', async () => {
it('Should resetSelectedItem', async () => {
const { result } = renderHook(
() => {
const { resetSelectedItem } = useSelectableList(selectableListScopeId);
const { resetSelectedItem } = useSelectableList(
selectableListComponentInstanceId,
);
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
selectableListScopeId,
selectableListComponentInstanceId,
);
const setSelectedItemId = useSetRecoilComponentStateV2(
selectedItemIdComponentState,
selectableListScopeId,
selectableListComponentInstanceId,
);
return {
resetSelectedItem,
@@ -6,7 +6,7 @@ import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/sta
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
type Direction = 'up' | 'down' | 'left' | 'right';
@@ -3,8 +3,8 @@ import { useRecoilCallback } from 'recoil';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isDefined } from 'twenty-shared/utils';
export const useSelectableList = (instanceId?: string) => {
@@ -1,8 +1,8 @@
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilCallback } from 'recoil';
import { Key } from 'ts-key-enum';
@@ -1,19 +0,0 @@
import { ReactNode } from 'react';
import { TabListScopeInternalContext } from './scope-internal-context/TabListScopeInternalContext';
type TabListScopeProps = {
children: ReactNode;
tabListScopeId: string;
};
export const TabListScope = ({
children,
tabListScopeId,
}: TabListScopeProps) => {
return (
<TabListScopeInternalContext.Provider value={{ scopeId: tabListScopeId }}>
{children}
</TabListScopeInternalContext.Provider>
);
};
@@ -1,7 +0,0 @@
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
type TabListScopeInternalContextProps = RecoilComponentStateKey;
export const TabListScopeInternalContext =
createScopeInternalContext<TabListScopeInternalContextProps>();
@@ -2,28 +2,28 @@ import { useRecoilCallback } from 'recoil';
import { isNavigationSectionOpenFamilyState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenFamilyState';
export const useNavigationSection = (scopeId: string) => {
export const useNavigationSection = (navigationSectionId: string) => {
const closeNavigationSection = useRecoilCallback(
({ set }) =>
() => {
set(isNavigationSectionOpenFamilyState(scopeId), false);
set(isNavigationSectionOpenFamilyState(navigationSectionId), false);
},
[scopeId],
[navigationSectionId],
);
const openNavigationSection = useRecoilCallback(
({ set }) =>
() => {
set(isNavigationSectionOpenFamilyState(scopeId), true);
set(isNavigationSectionOpenFamilyState(navigationSectionId), true);
},
[scopeId],
[navigationSectionId],
);
const toggleNavigationSection = useRecoilCallback(
({ snapshot }) =>
() => {
const isNavigationSectionOpen = snapshot
.getLoadable(isNavigationSectionOpenFamilyState(scopeId))
.getLoadable(isNavigationSectionOpenFamilyState(navigationSectionId))
.getValue();
if (isNavigationSectionOpen) {
@@ -32,11 +32,11 @@ export const useNavigationSection = (scopeId: string) => {
openNavigationSection();
}
},
[closeNavigationSection, openNavigationSection, scopeId],
[closeNavigationSection, openNavigationSection, navigationSectionId],
);
const isNavigationSectionOpenState =
isNavigationSectionOpenFamilyState(scopeId);
isNavigationSectionOpenFamilyState(navigationSectionId);
return {
isNavigationSectionOpenState,
@@ -1,33 +0,0 @@
import { useRef } from 'react';
import { v4 } from 'uuid';
import { RecoilScopeContext as RecoilScopeContextType } from '@/types/RecoilScopeContext';
import { RecoilScopeContext } from '../states/RecoilScopeContext';
/**
*
* @deprecated Use a custom scope context instead, see example with DropdownScope
*/
export const RecoilScope = ({
children,
scopeId,
CustomRecoilScopeContext,
}: {
children: React.ReactNode;
scopeId?: string;
CustomRecoilScopeContext?: RecoilScopeContextType;
}) => {
// eslint-disable-next-line @nx/workspace-no-state-useref
const currentScopeId = useRef(scopeId ?? v4());
return CustomRecoilScopeContext ? (
<CustomRecoilScopeContext.Provider value={currentScopeId.current}>
{children}
</CustomRecoilScopeContext.Provider>
) : (
<RecoilScopeContext.Provider value={currentScopeId.current}>
{children}
</RecoilScopeContext.Provider>
);
};
@@ -1,43 +0,0 @@
import { renderHook } from '@testing-library/react';
import { createContext } from 'react';
import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId';
const mockedContextValue = 'mocked-scope-id';
const MockedContext = createContext<string | null>(mockedContextValue);
const nullContext = createContext<string | null>(null);
const ERROR_MESSAGE =
'Using useContextScopedId outside of the specified context : undefined, verify that you are using a RecoilScope with the specific context you want to use.';
describe('useContextScopeId', () => {
it('Should return the scoped ID when used within the specified context', () => {
const { result } = renderHook(() => useContextScopeId(MockedContext), {
wrapper: ({ children }) => (
<MockedContext.Provider value={mockedContextValue}>
{children}
</MockedContext.Provider>
),
});
const scopeId = result.current;
expect(scopeId).toBe(mockedContextValue);
});
it('Should throw an error when used outside of the specified context', () => {
// Suppress console errors for this test since we're expecting an error
/* eslint-disable no-console */
const originalConsoleError = console.error;
console.error = jest.fn();
/* eslint-enable no-console */
expect(() => {
renderHook(() => useContextScopeId(nullContext));
}).toThrow(ERROR_MESSAGE);
// Restore console.error
/* eslint-disable no-console */
console.error = originalConsoleError;
/* eslint-enable no-console */
});
});
@@ -1,43 +0,0 @@
import { renderHook } from '@testing-library/react';
import { createContext } from 'react';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
const mockedContextValue = 'mocked-scope-id';
const MockedContext = createContext<string | null>(mockedContextValue);
const nullContext = createContext<string | null>(null);
const ERROR_MESSAGE =
'Using useRecoilScopeId outside of the specified context : undefined, verify that you are using a RecoilScope with the specific context you want to use.';
describe('useRecoilScopeId', () => {
it('Should return the scoped ID when used within the specified context', () => {
const { result } = renderHook(() => useRecoilScopeId(MockedContext), {
wrapper: ({ children }) => (
<MockedContext.Provider value={mockedContextValue}>
{children}
</MockedContext.Provider>
),
});
const scopeId = result.current;
expect(scopeId).toBe(mockedContextValue);
});
it('Should throw an error when used outside of the specified context', () => {
// Suppress console errors for this test since we're expecting an error
/* eslint-disable no-console */
const originalConsoleError = console.error;
console.error = jest.fn();
/* eslint-enable no-console */
expect(() => {
renderHook(() => useRecoilScopeId(nullContext));
}).toThrow(ERROR_MESSAGE);
// Restore console.error
/* eslint-disable no-console */
console.error = originalConsoleError;
/* eslint-enable no-console */
});
});
@@ -1,16 +0,0 @@
import { Context, useContext } from 'react';
/**
* @deprecated use a custom scope instead and desctructure the scope id from the scope context
* Get the scope context with useScopeInternalContext
*/
export const useContextScopeId = (SpecificContext: Context<string | null>) => {
const recoilScopeId = useContext(SpecificContext);
if (!recoilScopeId)
throw new Error(
`Using useContextScopedId outside of the specified context : ${SpecificContext.displayName}, verify that you are using a RecoilScope with the specific context you want to use.`,
);
return recoilScopeId;
};
@@ -1,17 +0,0 @@
import { useContext } from 'react';
import { RecoilScopeContext } from '@/types/RecoilScopeContext';
/**
* @deprecated Use a custom scope instead and desctructure the scope id from the scope context
*/
export const useRecoilScopeId = (RecoilScopeContext: RecoilScopeContext) => {
const recoilScopeId = useContext(RecoilScopeContext);
if (!recoilScopeId)
throw new Error(
`Using useRecoilScopeId outside of the specified context : ${RecoilScopeContext.displayName}, verify that you are using a RecoilScope with the specific context you want to use.`,
);
return recoilScopeId;
};
@@ -1,14 +0,0 @@
import { RecoilState, useRecoilState } from 'recoil';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
export const useRecoilScopedStateV2 = <StateType>(
recoilState: (scopedKey: RecoilComponentStateKey) => RecoilState<StateType>,
scopeId: string,
) => {
return useRecoilState<StateType>(
recoilState({
scopeId,
}),
);
};
@@ -1,64 +0,0 @@
import { renderHook } from '@testing-library/react';
import React from 'react';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
const mockScopeIdFrom = {
Props: 'scopeIdFromProps',
Context: 'scopeIdFromContext',
};
const MockedContext = createScopeInternalContext();
const errorMessage = 'Scope id is not provided and cannot be found in context.';
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<MockedContext.Provider value={{ scopeId: mockScopeIdFrom.Context }}>
{children}
</MockedContext.Provider>
);
describe('useAvailableScopeIdOrThrow', () => {
it('should return scopeIdFromProps if provided', () => {
const {
result: {
current: { availableScopeId },
},
} = renderHook(
() => ({
availableScopeId: useAvailableScopeIdOrThrow(
MockedContext,
mockScopeIdFrom.Props,
),
}),
{ wrapper: Wrapper },
);
expect(availableScopeId).toBe(mockScopeIdFrom.Props);
});
it('should return scopeIdFromContext if no scopeIdFromProps is present', () => {
const {
result: {
current: { availableScopeId },
},
} = renderHook(
() => ({
availableScopeId: useAvailableScopeIdOrThrow(MockedContext),
}),
{ wrapper: Wrapper },
);
expect(availableScopeId).toBe(mockScopeIdFrom.Context);
});
it('should throw an error if no scopeId is provided and scopeId is undefined in the context', () => {
global.console.error = jest.fn();
const renderFunction = () =>
renderHook(() => ({
availableScopeId: useAvailableScopeIdOrThrow(MockedContext),
}));
expect(renderFunction).toThrow(errorMessage);
});
});
@@ -1,32 +0,0 @@
import { renderHook } from '@testing-library/react';
import { useScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useScopeInternalContext';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
const scopeId = 'scopeId';
const MockedContext = createScopeInternalContext();
const Wrapper = ({ children }: { children: React.ReactNode }) => (
<MockedContext.Provider value={{ scopeId }}>
{children}
</MockedContext.Provider>
);
describe('useScopeInternalContext', () => {
it('should work as expected', () => {
const {
result: {
current: { scopeInternalContext },
},
} = renderHook(
() => ({
scopeInternalContext: useScopeInternalContext(MockedContext),
}),
{
wrapper: Wrapper,
},
);
expect(scopeInternalContext!.scopeId).toBe(scopeId);
});
});
@@ -1,26 +0,0 @@
import { isNonEmptyString } from '@sniptt/guards';
import { ScopeInternalContext } from '../types/ScopeInternalContext';
import { useScopeInternalContext } from './useScopeInternalContext';
export const useAvailableScopeIdOrThrow = <T extends { scopeId: string }>(
Context: ScopeInternalContext<T>,
scopeIdFromProps?: string,
): string => {
const scopeInternalContext = useScopeInternalContext(Context);
const scopeIdFromContext = scopeInternalContext?.scopeId;
if (isNonEmptyString(scopeIdFromProps)) {
return scopeIdFromProps;
} else if (isNonEmptyString(scopeIdFromContext)) {
return scopeIdFromContext;
} else {
throw new Error(
`Scope id is not provided and cannot be found in context.\n` +
`Context: ${Context.displayName || 'Unknown'}\n` +
`ScopeInternalContext.scopeId: ${scopeInternalContext?.scopeId || 'Unknown'}`,
);
}
};
@@ -1,11 +0,0 @@
import { useContext } from 'react';
import { ScopeInternalContext } from '../types/ScopeInternalContext';
export const useScopeInternalContext = <T extends { scopeId: string }>(
Context: ScopeInternalContext<T>,
) => {
const context = useContext(Context);
return context;
};
@@ -1,4 +0,0 @@
import { Context } from 'react';
export type ScopeInternalContext<T extends { scopeId: string }> =
Context<T | null>;
@@ -1,13 +0,0 @@
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
import { Context, createContext } from 'react';
type ScopeInternalContext<T extends RecoilComponentStateKey> =
Context<T | null>;
export const createScopeInternalContext = <T extends RecoilComponentStateKey>(
initialValue?: T,
) => {
return createContext<T | null>(
initialValue ?? null,
) as ScopeInternalContext<T>;
};
@@ -1,3 +0,0 @@
import { createContext } from 'react';
export const RecoilScopeContext = createContext<string | null>(null);
@@ -1,7 +0,0 @@
import { RecoilValueReadOnly } from 'recoil';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
export type RecoilScopedSelector<StateType> = (
scopedKey: RecoilComponentStateKey,
) => RecoilValueReadOnly<StateType>;
@@ -1,7 +0,0 @@
import { RecoilState } from 'recoil';
import { RecoilComponentStateKey } from '@/ui/utilities/state/component-state/types/RecoilComponentStateKey';
export type RecoilScopedState<StateType> = (
scopedKey: RecoilComponentStateKey,
) => RecoilState<StateType>;
@@ -1,10 +0,0 @@
import { RecoilScopedState } from '../types/RecoilScopedState';
export const getScopedStateDeprecated = <StateType>(
recoilScopedState: RecoilScopedState<StateType>,
scopeId: string,
) => {
return recoilScopedState({
scopeId,
});
};
@@ -1,8 +0,0 @@
import { RecoilState, RecoilValueReadOnly, Snapshot } from 'recoil';
export const getSnapshotValue = <StateType>(
snapshot: Snapshot,
state: RecoilState<StateType> | RecoilValueReadOnly<StateType>,
) => {
return snapshot.getLoadable(state).getValue();
};
@@ -1,8 +0,0 @@
import { DefaultValue } from 'recoil';
export const guardRecoilDefaultValue = (
candidate: any,
): candidate is DefaultValue => {
if (candidate instanceof DefaultValue) return true;
return false;
};
@@ -1,34 +0,0 @@
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { ComponentFamilyState } from '@/ui/utilities/state/component-state/types/ComponentFamilyState';
import { SerializableParam } from 'recoil';
export const useExtractedComponentFamilyStateV2 = <
FamilyKey extends SerializableParam,
Value,
>(
componentFamilyState: ComponentFamilyState<Value, FamilyKey>,
componentId?: string,
) => {
const componentContext = (window as any).componentContextStateMap?.get(
componentFamilyState.key,
);
if (!componentContext) {
throw new Error(
`Component context for key "${componentFamilyState.key}" is not defined`,
);
}
const internalScopeId = useAvailableScopeIdOrThrow(
componentContext,
componentId,
);
const extractedComponentFamilyState = (familyKey: FamilyKey) =>
componentFamilyState.atomFamily({
scopeId: internalScopeId,
familyKey,
});
return extractedComponentFamilyState;
};
@@ -1,35 +0,0 @@
import { SerializableParam, useRecoilValue } from 'recoil';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { ComponentFamilyState } from '@/ui/utilities/state/component-state/types/ComponentFamilyState';
export const useRecoilComponentFamilyValue = <
StateType,
FamilyKey extends SerializableParam,
>(
componentFamilyState: ComponentFamilyState<StateType, FamilyKey>,
familyKey: FamilyKey,
componentId?: string,
) => {
const componentContext = (window as any).componentContextStateMap?.get(
componentFamilyState.key,
);
if (!componentContext) {
throw new Error(
`Component context for key "${componentFamilyState.key}" is not defined`,
);
}
const internalComponentId = useAvailableScopeIdOrThrow(
componentContext,
componentId,
);
return useRecoilValue(
componentFamilyState.atomFamily({
scopeId: internalComponentId,
familyKey,
}),
);
};

Some files were not shown because too many files have changed in this diff Show More