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:
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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}
|
||||
|
||||
+5
-3
@@ -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>
|
||||
|
||||
+2
-4
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
-20
@@ -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>
|
||||
);
|
||||
};
|
||||
+5
-3
@@ -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,
|
||||
),
|
||||
[],
|
||||
);
|
||||
+1
-1
@@ -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:
|
||||
|
||||
+35
-44
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
-8
@@ -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(() => {
|
||||
|
||||
+1
-1
@@ -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(
|
||||
|
||||
+4
-4
@@ -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);
|
||||
|
||||
-33
@@ -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>
|
||||
);
|
||||
};
|
||||
-13
@@ -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>();
|
||||
+1
-4
@@ -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 = {};
|
||||
|
||||
+1
-6
@@ -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());
|
||||
|
||||
|
||||
+2
-2
@@ -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(() => {
|
||||
|
||||
+2
-2
@@ -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
-1
@@ -1,6 +1,6 @@
|
||||
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
|
||||
|
||||
export const isInlineCellInEditModeScopedState = createFamilyState<
|
||||
export const isInlineCellInEditModeFamilyState = createFamilyState<
|
||||
boolean,
|
||||
string
|
||||
>({
|
||||
+1
-3
@@ -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
-38
@@ -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}>
|
||||
|
||||
+32
-35
@@ -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'
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+30
-33
@@ -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'
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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) => {
|
||||
|
||||
+1
-1
@@ -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(
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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) => {
|
||||
|
||||
+1
-1
@@ -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 = ({
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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 = () => {
|
||||
|
||||
-1
@@ -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;
|
||||
};
|
||||
|
||||
+3
-3
@@ -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
-3
@@ -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>
|
||||
);
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
+2
-2
@@ -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,
|
||||
},
|
||||
|
||||
+5
-3
@@ -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>
|
||||
|
||||
+2
-4
@@ -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: {
|
||||
|
||||
+2
-8
@@ -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: {
|
||||
|
||||
+3
-8
@@ -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: {
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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
-3
@@ -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>
|
||||
);
|
||||
|
||||
+5
-3
@@ -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
-3
@@ -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>
|
||||
);
|
||||
|
||||
-2
@@ -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
-3
@@ -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>
|
||||
);
|
||||
|
||||
+5
-3
@@ -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
@@ -1 +0,0 @@
|
||||
export const DIALOG_MANAGER_HOTKEY_SCOPE_MEMOIZE_KEY = 'dialog-manager';
|
||||
+5
-4
@@ -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>
|
||||
);
|
||||
|
||||
|
||||
-21
@@ -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>
|
||||
);
|
||||
};
|
||||
-21
@@ -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>
|
||||
);
|
||||
};
|
||||
-7
@@ -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>();
|
||||
+9
-7
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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>
|
||||
);
|
||||
};
|
||||
-7
@@ -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>();
|
||||
+8
-8
@@ -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,
|
||||
|
||||
-33
@@ -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>
|
||||
);
|
||||
};
|
||||
-43
@@ -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 */
|
||||
});
|
||||
});
|
||||
-43
@@ -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 */
|
||||
});
|
||||
});
|
||||
-16
@@ -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;
|
||||
};
|
||||
-14
@@ -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,
|
||||
}),
|
||||
);
|
||||
};
|
||||
-64
@@ -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);
|
||||
});
|
||||
});
|
||||
-32
@@ -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);
|
||||
});
|
||||
});
|
||||
-26
@@ -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'}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
-11
@@ -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;
|
||||
};
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
import { Context } from 'react';
|
||||
|
||||
export type ScopeInternalContext<T extends { scopeId: string }> =
|
||||
Context<T | null>;
|
||||
-13
@@ -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>;
|
||||
};
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const RecoilScopeContext = createContext<string | null>(null);
|
||||
-7
@@ -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>;
|
||||
-10
@@ -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();
|
||||
};
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
import { DefaultValue } from 'recoil';
|
||||
|
||||
export const guardRecoilDefaultValue = (
|
||||
candidate: any,
|
||||
): candidate is DefaultValue => {
|
||||
if (candidate instanceof DefaultValue) return true;
|
||||
return false;
|
||||
};
|
||||
-34
@@ -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;
|
||||
};
|
||||
-35
@@ -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
Reference in New Issue
Block a user