583 refactor useCommandMenu hook (#10984)
Closes https://github.com/twentyhq/core-team-issues/issues/583 - Split hook into smaller hooks - Create tests
This commit is contained in:
@ -38,11 +38,11 @@ const StyledSeparator = styled.div<{ size: 'sm' | 'md' }>`
|
||||
|
||||
export const RecordIndexActionMenuBarAllActionsButton = () => {
|
||||
const theme = useTheme();
|
||||
const { openRootCommandMenu } = useCommandMenu();
|
||||
const { openCommandMenu } = useCommandMenu();
|
||||
return (
|
||||
<>
|
||||
<StyledSeparator size="md" />
|
||||
<StyledButton onClick={openRootCommandMenu}>
|
||||
<StyledButton onClick={openCommandMenu}>
|
||||
<IconLayoutSidebarRightExpand size={theme.icon.size.md} />
|
||||
<StyledButtonLabel>All Actions</StyledButtonLabel>
|
||||
<StyledSeparator size="sm" />
|
||||
|
||||
@ -10,7 +10,7 @@ import { getCalendarEventEndDate } from '@/activities/calendar/utils/getCalendar
|
||||
import { getCalendarEventStartDate } from '@/activities/calendar/utils/getCalendarEventStartDate';
|
||||
import { hasCalendarEventEnded } from '@/activities/calendar/utils/hasCalendarEventEnded';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenCalendarEventInCommandMenu } from '@/command-menu/hooks/useOpenCalendarEventInCommandMenu';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import {
|
||||
Avatar,
|
||||
@ -114,7 +114,8 @@ export const CalendarEventRow = ({
|
||||
const theme = useTheme();
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const { displayCurrentEventCursor = false } = useContext(CalendarContext);
|
||||
const { openCalendarEventInCommandMenu } = useCommandMenu();
|
||||
const { openCalendarEventInCommandMenu } =
|
||||
useOpenCalendarEventInCommandMenu();
|
||||
|
||||
const startsAt = getCalendarEventStartDate(calendarEvent);
|
||||
const endsAt = getCalendarEventEndDate(calendarEvent);
|
||||
|
||||
@ -3,7 +3,7 @@ import { Avatar, GRAY_SCALE } from 'twenty-ui';
|
||||
|
||||
import { ActivityRow } from '@/activities/components/ActivityRow';
|
||||
import { EmailThreadNotShared } from '@/activities/emails/components/EmailThreadNotShared';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenEmailThreadInCommandMenu } from '@/command-menu/hooks/useOpenEmailThreadInCommandMenu';
|
||||
import { MessageChannelVisibility, TimelineThread } from '~/generated/graphql';
|
||||
import { formatToHumanReadableDate } from '~/utils/date-utils';
|
||||
|
||||
@ -68,7 +68,7 @@ type EmailThreadPreviewProps = {
|
||||
};
|
||||
|
||||
export const EmailThreadPreview = ({ thread }: EmailThreadPreviewProps) => {
|
||||
const { openEmailThreadInCommandMenu } = useCommandMenu();
|
||||
const { openEmailThreadInCommandMenu } = useOpenEmailThreadInCommandMenu();
|
||||
|
||||
const visibility = thread.visibility;
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { activityTargetableEntityArrayState } from '@/activities/states/activityTargetableEntityArrayState';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||
@ -13,6 +12,7 @@ import { Note } from '@/activities/types/Note';
|
||||
import { NoteTarget } from '@/activities/types/NoteTarget';
|
||||
import { Task } from '@/activities/types/Task';
|
||||
import { TaskTarget } from '@/activities/types/TaskTarget';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { isNewViewableRecordLoadingState } from '@/object-record/record-right-drawer/states/isNewViewableRecordLoading';
|
||||
|
||||
@ -53,7 +53,7 @@ export const useOpenCreateActivityDrawer = ({
|
||||
isUpsertingActivityInDBState,
|
||||
);
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const openCreateActivityDrawer = async ({
|
||||
targetableObjects,
|
||||
|
||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
||||
import { ActivityTargetsInlineCell } from '@/activities/inline-cell/components/ActivityTargetsInlineCell';
|
||||
import { Note } from '@/activities/types/Note';
|
||||
import { getActivityPreview } from '@/activities/utils/getActivityPreview';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
|
||||
@ -68,7 +68,7 @@ export const NoteCard = ({
|
||||
note: Note;
|
||||
isSingleNote: boolean;
|
||||
}) => {
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const body = getActivityPreview(note?.bodyV2?.blocknote ?? null);
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import { beautifyExactDate, hasDatePassed } from '~/utils/date-utils';
|
||||
|
||||
import { ActivityRow } from '@/activities/components/ActivityRow';
|
||||
import { Task } from '@/activities/types/Task';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
import { useCompleteTask } from '../hooks/useCompleteTask';
|
||||
@ -78,7 +78,7 @@ const StyledCheckboxContainer = styled.div`
|
||||
|
||||
export const TaskRow = ({ task }: { task: Task }) => {
|
||||
const theme = useTheme();
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const body = getActivitySummary(task?.bodyV2?.blocknote ?? null);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import {
|
||||
StyledEventRowItemAction,
|
||||
StyledEventRowItemColumn,
|
||||
} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
@ -55,7 +55,7 @@ export const EventRowActivity = ({
|
||||
? event.linkedRecordCachedName
|
||||
: 'Untitled';
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@ -9,6 +9,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
|
||||
import { COMMAND_MENU_ANIMATION_VARIANTS } from '@/command-menu/constants/CommandMenuAnimationVariants';
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
@ -54,11 +55,10 @@ export const CommandMenuContainer = ({
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const {
|
||||
toggleCommandMenu,
|
||||
closeCommandMenu,
|
||||
onCommandMenuCloseAnimationComplete,
|
||||
} = useCommandMenu();
|
||||
const { toggleCommandMenu, closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
|
||||
@ -154,7 +154,7 @@ export const CommandMenuContainer = ({
|
||||
<ActionMenuConfirmationModals />
|
||||
<AnimatePresence
|
||||
mode="wait"
|
||||
onExitComplete={onCommandMenuCloseAnimationComplete}
|
||||
onExitComplete={commandMenuCloseAnimationCompleteCleanup}
|
||||
>
|
||||
{isCommandMenuOpened && (
|
||||
<StyledCommandMenu
|
||||
|
||||
@ -23,7 +23,7 @@ export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
||||
limit: 3,
|
||||
});
|
||||
|
||||
const { openRootCommandMenu } = useCommandMenu();
|
||||
const { openCommandMenu } = useCommandMenu();
|
||||
|
||||
if (loading) {
|
||||
return null;
|
||||
@ -46,7 +46,7 @@ export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
||||
totalCount,
|
||||
),
|
||||
Icons: Avatars,
|
||||
onClick: contextChips.length > 0 ? openRootCommandMenu : undefined,
|
||||
onClick: contextChips.length > 0 ? openCommandMenu : undefined,
|
||||
withIconBackground: false,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
@ -7,6 +7,7 @@ import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/Command
|
||||
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuContextChips } from '@/command-menu/hooks/useCommandMenuContextChips';
|
||||
import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistory';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
@ -91,7 +92,9 @@ export const CommandMenuTopBar = () => {
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const { closeCommandMenu, goBackFromCommandMenu } = useCommandMenu();
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const { goBackFromCommandMenu } = useCommandMenuHistory();
|
||||
|
||||
const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
|
||||
@ -8,8 +8,6 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { IconList, IconSearch } from 'twenty-ui';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
@ -53,7 +51,7 @@ describe('useCommandMenu', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.openRootCommandMenu();
|
||||
result.current.commandMenu.openCommandMenu();
|
||||
});
|
||||
|
||||
expect(result.current.isCommandMenuOpened).toBe(true);
|
||||
@ -82,164 +80,4 @@ describe('useCommandMenu', () => {
|
||||
|
||||
expect(result.current.isCommandMenuOpened).toBe(false);
|
||||
});
|
||||
|
||||
it('should navigate to a page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Search',
|
||||
Icon: IconSearch,
|
||||
instanceId: '1',
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
{
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Company',
|
||||
Icon: IconList,
|
||||
instanceId: '2',
|
||||
});
|
||||
});
|
||||
|
||||
it('should go back from a page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
{
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
},
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.goBackFromCommandMenu();
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Search',
|
||||
Icon: IconSearch,
|
||||
instanceId: '1',
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.goBackFromCommandMenu();
|
||||
result.current.commandMenu.onCommandMenuCloseAnimationComplete();
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
instanceId: '',
|
||||
Icon: undefined,
|
||||
});
|
||||
expect(result.current.isCommandMenuOpened).toBe(false);
|
||||
});
|
||||
|
||||
it('should navigate to a page in history', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenuHistory(0);
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Search',
|
||||
Icon: IconSearch,
|
||||
instanceId: '1',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -0,0 +1,249 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId';
|
||||
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { IconList } from 'twenty-ui';
|
||||
|
||||
const mockCloseDropdown = jest.fn();
|
||||
const mockResetContextStoreStates = jest.fn();
|
||||
const mockResetSelectedItem = jest.fn();
|
||||
const mockGoBackToPreviousHotkeyScope = jest.fn();
|
||||
const mockEmitRightDrawerCloseEvent = jest.fn();
|
||||
|
||||
jest.mock('@/ui/layout/dropdown/hooks/useDropdownV2', () => ({
|
||||
useDropdownV2: () => ({
|
||||
closeDropdown: mockCloseDropdown,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@/command-menu/hooks/useResetContextStoreStates', () => ({
|
||||
useResetContextStoreStates: () => ({
|
||||
resetContextStoreStates: mockResetContextStoreStates,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@/ui/layout/selectable-list/hooks/useSelectableList', () => ({
|
||||
useSelectableList: () => ({
|
||||
resetSelectedItem: mockResetSelectedItem,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope', () => ({
|
||||
usePreviousHotkeyScope: () => ({
|
||||
goBackToPreviousHotkeyScope: mockGoBackToPreviousHotkeyScope,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent', () => ({
|
||||
emitRightDrawerCloseEvent: () => {
|
||||
mockEmitRightDrawerCloseEvent();
|
||||
},
|
||||
}));
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
describe('useCommandMenuCloseAnimationCompleteCleanup', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
const commandMenuNavigationRecords = useRecoilValue(
|
||||
commandMenuNavigationRecordsState,
|
||||
);
|
||||
const commandMenuNavigationMorphItemByPage = useRecoilValue(
|
||||
commandMenuNavigationMorphItemByPageState,
|
||||
);
|
||||
const hasUserSelectedCommand = useRecoilValue(
|
||||
hasUserSelectedCommandState,
|
||||
);
|
||||
const isCommandMenuClosing = useRecoilValue(isCommandMenuClosingState);
|
||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||
|
||||
// Get setters for state modification in tests
|
||||
const setCommandMenuPage = useSetRecoilState(commandMenuPageState);
|
||||
const setCommandMenuPageInfo = useSetRecoilState(
|
||||
commandMenuPageInfoState,
|
||||
);
|
||||
const setIsCommandMenuOpened = useSetRecoilState(
|
||||
isCommandMenuOpenedState,
|
||||
);
|
||||
const setCommandMenuSearch = useSetRecoilState(commandMenuSearchState);
|
||||
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
const setCommandMenuNavigationRecords = useSetRecoilState(
|
||||
commandMenuNavigationRecordsState,
|
||||
);
|
||||
const setHasUserSelectedCommand = useSetRecoilState(
|
||||
hasUserSelectedCommandState,
|
||||
);
|
||||
const setIsCommandMenuClosing = useSetRecoilState(
|
||||
isCommandMenuClosingState,
|
||||
);
|
||||
const setViewableRecordId = useSetRecoilState(viewableRecordIdState);
|
||||
|
||||
return {
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
commandMenuPage,
|
||||
commandMenuPageInfo,
|
||||
isCommandMenuOpened,
|
||||
commandMenuSearch,
|
||||
commandMenuNavigationStack,
|
||||
commandMenuNavigationRecords,
|
||||
commandMenuNavigationMorphItemByPage,
|
||||
hasUserSelectedCommand,
|
||||
isCommandMenuClosing,
|
||||
viewableRecordId,
|
||||
setCommandMenuPage,
|
||||
setCommandMenuPageInfo,
|
||||
setIsCommandMenuOpened,
|
||||
setCommandMenuSearch,
|
||||
setCommandMenuNavigationStack,
|
||||
setCommandMenuNavigationRecords,
|
||||
setHasUserSelectedCommand,
|
||||
setIsCommandMenuClosing,
|
||||
setViewableRecordId,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: Wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
it('should reset modified states back to default values', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.setCommandMenuPage(CommandMenuPages.ViewRecord);
|
||||
result.current.setCommandMenuPageInfo({
|
||||
title: 'Test Record',
|
||||
Icon: IconList,
|
||||
instanceId: 'test-id',
|
||||
});
|
||||
result.current.setIsCommandMenuOpened(true);
|
||||
result.current.setCommandMenuSearch('test search');
|
||||
result.current.setCommandMenuNavigationStack([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconList,
|
||||
pageId: '1',
|
||||
},
|
||||
]);
|
||||
result.current.setCommandMenuNavigationRecords([
|
||||
{
|
||||
objectMetadataItem: { id: '1', nameSingular: 'Record' } as any,
|
||||
record: { id: '1' } as any,
|
||||
},
|
||||
]);
|
||||
result.current.setHasUserSelectedCommand(true);
|
||||
result.current.setIsCommandMenuClosing(true);
|
||||
result.current.setViewableRecordId('record-123');
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Test Record',
|
||||
Icon: IconList,
|
||||
instanceId: 'test-id',
|
||||
});
|
||||
expect(result.current.isCommandMenuOpened).toBe(true);
|
||||
expect(result.current.commandMenuSearch).toBe('test search');
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconList,
|
||||
pageId: '1',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuNavigationRecords).toEqual([
|
||||
{
|
||||
objectMetadataItem: { id: '1', nameSingular: 'Record' } as any,
|
||||
record: { id: '1' } as any,
|
||||
},
|
||||
]);
|
||||
expect(result.current.hasUserSelectedCommand).toBe(true);
|
||||
expect(result.current.isCommandMenuClosing).toBe(true);
|
||||
expect(result.current.viewableRecordId).toBe('record-123');
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenuCloseAnimationCompleteCleanup();
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
expect(result.current.isCommandMenuOpened).toBe(false);
|
||||
expect(result.current.commandMenuSearch).toBe('');
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([]);
|
||||
expect(result.current.commandMenuNavigationRecords).toEqual([]);
|
||||
expect(result.current.hasUserSelectedCommand).toBe(false);
|
||||
expect(result.current.isCommandMenuClosing).toBe(false);
|
||||
expect(result.current.viewableRecordId).toBe(null);
|
||||
});
|
||||
|
||||
it('should call all dependent functions correctly', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenuCloseAnimationCompleteCleanup();
|
||||
});
|
||||
|
||||
expect(mockCloseDropdown).toHaveBeenCalledTimes(1);
|
||||
expect(mockResetContextStoreStates).toHaveBeenCalledTimes(2);
|
||||
expect(mockResetSelectedItem).toHaveBeenCalledTimes(1);
|
||||
expect(mockGoBackToPreviousHotkeyScope).toHaveBeenCalledTimes(1);
|
||||
expect(mockEmitRightDrawerCloseEvent).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(mockCloseDropdown).toHaveBeenCalledWith(
|
||||
COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID,
|
||||
);
|
||||
expect(mockResetContextStoreStates).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
);
|
||||
expect(mockResetContextStoreStates).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID,
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,147 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RecoilRoot, useRecoilValue } from 'recoil';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistory';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { IconList, IconSearch } from 'twenty-ui';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const commandMenu = useCommandMenu();
|
||||
const commandMenuHistory = useCommandMenuHistory();
|
||||
const commandMenuCloseAnimationCompleteCleanup =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
|
||||
|
||||
return {
|
||||
commandMenu,
|
||||
commandMenuHistory,
|
||||
isCommandMenuOpened,
|
||||
commandMenuNavigationStack,
|
||||
commandMenuPage,
|
||||
commandMenuPageInfo,
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: Wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useCommandMenuHistory', () => {
|
||||
it('should go back from a page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
{
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Company',
|
||||
pageIcon: IconList,
|
||||
pageId: '2',
|
||||
},
|
||||
]);
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenuHistory.goBackFromCommandMenu();
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Search',
|
||||
Icon: IconSearch,
|
||||
instanceId: '1',
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenuHistory.goBackFromCommandMenu();
|
||||
result.current.commandMenuCloseAnimationCompleteCleanup.commandMenuCloseAnimationCompleteCleanup();
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([]);
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
instanceId: '',
|
||||
Icon: undefined,
|
||||
});
|
||||
expect(result.current.isCommandMenuOpened).toBe(false);
|
||||
});
|
||||
|
||||
it('should navigate to a page in history', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenu.navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: '1',
|
||||
});
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.commandMenuHistory.navigateCommandMenuHistory(0);
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.SearchRecords);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Search',
|
||||
Icon: IconSearch,
|
||||
instanceId: '1',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,101 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { Icon123, useIcons } from 'twenty-ui';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||
}));
|
||||
|
||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 0,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
const commandMenuNavigationStack = useRecoilValue(
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
|
||||
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
return {
|
||||
navigateCommandMenu,
|
||||
commandMenuPage,
|
||||
commandMenuNavigationStack,
|
||||
commandMenuPageInfo,
|
||||
getIcon,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useNavigateCommandMenu', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should navigate to the correct page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.navigateCommandMenu({
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'Root',
|
||||
pageIcon: Icon123,
|
||||
pageIconColor: 'red',
|
||||
pageId: 'mocked-uuid',
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.Root);
|
||||
expect(result.current.commandMenuNavigationStack).toEqual([
|
||||
{
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'Root',
|
||||
pageIcon: Icon123,
|
||||
pageIconColor: 'red',
|
||||
pageId: 'mocked-uuid',
|
||||
},
|
||||
]);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: 'Root',
|
||||
Icon: Icon123,
|
||||
instanceId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,89 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useOpenCalendarEventInCommandMenu } from '@/command-menu/hooks/useOpenCalendarEventInCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { IconCalendarEvent } from 'twenty-ui';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||
}));
|
||||
|
||||
const mockNavigateCommandMenu = jest.fn();
|
||||
jest.mock('@/command-menu/hooks/useNavigateCommandMenu', () => ({
|
||||
useNavigateCommandMenu: () => ({
|
||||
navigateCommandMenu: mockNavigateCommandMenu,
|
||||
}),
|
||||
}));
|
||||
|
||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 0,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { openCalendarEventInCommandMenu } =
|
||||
useOpenCalendarEventInCommandMenu();
|
||||
|
||||
const viewableRecordId = useRecoilComponentValueV2(
|
||||
viewableRecordIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
|
||||
return {
|
||||
openCalendarEventInCommandMenu,
|
||||
viewableRecordId,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useOpenCalendarEventInCommandMenu', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should set the correct states and navigate to the calendar event page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
const calendarEventId = 'calendar-event-123';
|
||||
|
||||
act(() => {
|
||||
result.current.openCalendarEventInCommandMenu(calendarEventId);
|
||||
});
|
||||
|
||||
expect(result.current.viewableRecordId).toBe(calendarEventId);
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.ViewCalendarEvent,
|
||||
pageTitle: 'Calendar Event',
|
||||
pageIcon: IconCalendarEvent,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,89 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useOpenEmailThreadInCommandMenu } from '@/command-menu/hooks/useOpenEmailThreadInCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { IconMail } from 'twenty-ui';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||
}));
|
||||
|
||||
const mockNavigateCommandMenu = jest.fn();
|
||||
jest.mock('@/command-menu/hooks/useNavigateCommandMenu', () => ({
|
||||
useNavigateCommandMenu: () => ({
|
||||
navigateCommandMenu: mockNavigateCommandMenu,
|
||||
}),
|
||||
}));
|
||||
|
||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 0,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { openEmailThreadInCommandMenu } =
|
||||
useOpenEmailThreadInCommandMenu();
|
||||
|
||||
const viewableRecordId = useRecoilComponentValueV2(
|
||||
viewableRecordIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
|
||||
return {
|
||||
openEmailThreadInCommandMenu,
|
||||
viewableRecordId,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useOpenEmailThreadInCommandMenu', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should set the correct states and navigate to the email thread page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
const emailThreadId = 'email-thread-123';
|
||||
|
||||
act(() => {
|
||||
result.current.openEmailThreadInCommandMenu(emailThreadId);
|
||||
});
|
||||
|
||||
expect(result.current.viewableRecordId).toBe(emailThreadId);
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.ViewEmailThread,
|
||||
pageTitle: 'Email Thread',
|
||||
pageIcon: IconMail,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,178 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useIcons } from 'twenty-ui';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||
}));
|
||||
|
||||
const mockNavigateCommandMenu = jest.fn();
|
||||
jest.mock('@/command-menu/hooks/useNavigateCommandMenu', () => ({
|
||||
useNavigateCommandMenu: () => ({
|
||||
navigateCommandMenu: mockNavigateCommandMenu,
|
||||
}),
|
||||
}));
|
||||
|
||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 0,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
const commandMenuNavigationMorphItemByPage = useRecoilValue(
|
||||
commandMenuNavigationMorphItemByPageState,
|
||||
);
|
||||
|
||||
const viewableRecordId = useRecoilComponentValueV2(
|
||||
viewableRecordIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const viewableRecordNameSingular = useRecoilComponentValueV2(
|
||||
viewableRecordNameSingularComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const currentObjectMetadataItemId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const targetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const numberOfSelectedRecords = useRecoilComponentValueV2(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const currentViewType = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewTypeComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
return {
|
||||
openRecordInCommandMenu,
|
||||
viewableRecordId,
|
||||
commandMenuPage,
|
||||
commandMenuNavigationMorphItemByPage,
|
||||
viewableRecordNameSingular,
|
||||
currentObjectMetadataItemId,
|
||||
targetedRecordsRule,
|
||||
numberOfSelectedRecords,
|
||||
currentViewType,
|
||||
getIcon,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useOpenRecordInCommandMenu', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should set the correct states and navigate to the record page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
const recordId = 'record-123';
|
||||
const objectNameSingular = 'person';
|
||||
|
||||
act(() => {
|
||||
result.current.openRecordInCommandMenu({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.viewableRecordId).toBe(recordId);
|
||||
expect(result.current.viewableRecordNameSingular).toBe(objectNameSingular);
|
||||
expect(result.current.currentObjectMetadataItemId).toBe(
|
||||
personMockObjectMetadataItem.id,
|
||||
);
|
||||
expect(result.current.targetedRecordsRule).toEqual({
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [recordId],
|
||||
});
|
||||
expect(result.current.numberOfSelectedRecords).toBe(1);
|
||||
expect(result.current.currentViewType).toBe(ContextStoreViewType.ShowPage);
|
||||
|
||||
expect(result.current.commandMenuNavigationMorphItemByPage.size).toBe(1);
|
||||
expect(
|
||||
result.current.commandMenuNavigationMorphItemByPage.get('mocked-uuid'),
|
||||
).toEqual({
|
||||
objectMetadataId: personMockObjectMetadataItem.id,
|
||||
recordId,
|
||||
});
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'Person',
|
||||
pageIcon: result.current.getIcon(personMockObjectMetadataItem.icon),
|
||||
pageIconColor: 'currentColor',
|
||||
pageId: 'mocked-uuid',
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the correct page title for a new record', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
const recordId = 'new-record-123';
|
||||
const objectNameSingular = 'person';
|
||||
|
||||
act(() => {
|
||||
result.current.openRecordInCommandMenu({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
isNewRecord: true,
|
||||
});
|
||||
});
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: 'New Person',
|
||||
pageIcon: result.current.getIcon(personMockObjectMetadataItem.icon),
|
||||
pageIconColor: 'currentColor',
|
||||
pageId: 'mocked-uuid',
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,157 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
|
||||
import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import { getPeopleRecordConnectionMock } from '~/testing/mock-data/people';
|
||||
|
||||
const mockCopyContextStoreStates = jest.fn();
|
||||
jest.mock(
|
||||
'@/command-menu/hooks/useCopyContextStoreAndActionMenuStates',
|
||||
() => ({
|
||||
useCopyContextStoreStates: () => ({
|
||||
copyContextStoreStates: mockCopyContextStoreStates,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
const personMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const peopleMock = getPeopleRecordConnectionMock();
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
personMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [peopleMock[0].id, peopleMock[1].id],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 2,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(recordStoreFamilyState(peopleMock[0].id), peopleMock[0]);
|
||||
snapshot.set(recordStoreFamilyState(peopleMock[1].id), peopleMock[1]);
|
||||
},
|
||||
});
|
||||
|
||||
describe('useSetGlobalCommandMenuContext', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should reset all command menu context states', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { setGlobalCommandMenuContext } =
|
||||
useSetGlobalCommandMenuContext();
|
||||
|
||||
const targetedRecordsRule = useRecoilValue(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
|
||||
const numberOfSelectedRecords = useRecoilValue(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
|
||||
const filters = useRecoilValue(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
|
||||
const currentViewType = useRecoilValue(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
);
|
||||
|
||||
const commandMenuPageInfo = useRecoilValue(commandMenuPageInfoState);
|
||||
|
||||
const hasUserSelectedCommand = useRecoilValue(
|
||||
hasUserSelectedCommandState,
|
||||
);
|
||||
|
||||
return {
|
||||
setGlobalCommandMenuContext,
|
||||
targetedRecordsRule,
|
||||
numberOfSelectedRecords,
|
||||
filters,
|
||||
currentViewType,
|
||||
commandMenuPageInfo,
|
||||
hasUserSelectedCommand,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.current.targetedRecordsRule).toEqual({
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [peopleMock[0].id, peopleMock[1].id],
|
||||
});
|
||||
expect(result.current.numberOfSelectedRecords).toBe(2);
|
||||
expect(result.current.filters).toEqual([]);
|
||||
expect(result.current.currentViewType).toBe(ContextStoreViewType.Table);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
expect(result.current.hasUserSelectedCommand).toBe(false);
|
||||
|
||||
act(() => {
|
||||
result.current.setGlobalCommandMenuContext();
|
||||
});
|
||||
|
||||
expect(result.current.targetedRecordsRule).toEqual({
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
});
|
||||
expect(result.current.numberOfSelectedRecords).toBe(0);
|
||||
expect(result.current.filters).toEqual([]);
|
||||
expect(result.current.currentViewType).toBe(ContextStoreViewType.Table);
|
||||
expect(result.current.commandMenuPageInfo).toEqual({
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
expect(result.current.hasUserSelectedCommand).toBe(false);
|
||||
});
|
||||
|
||||
it('should call copyContextStoreStates with correct parameters', () => {
|
||||
const { result } = renderHook(() => useSetGlobalCommandMenuContext(), {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.setGlobalCommandMenuContext();
|
||||
});
|
||||
|
||||
expect(mockCopyContextStoreStates).toHaveBeenCalledWith({
|
||||
instanceIdToCopyFrom: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,207 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
||||
import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { act } from 'react';
|
||||
import { IconBolt, IconSettingsAutomation, useIcons } from 'twenty-ui';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndActionMenuWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import { useWorkflowCommandMenu } from '../useWorkflowCommandMenu';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('mocked-uuid'),
|
||||
}));
|
||||
|
||||
const mockNavigateCommandMenu = jest.fn();
|
||||
jest.mock('@/command-menu/hooks/useNavigateCommandMenu', () => ({
|
||||
useNavigateCommandMenu: () => ({
|
||||
navigateCommandMenu: mockNavigateCommandMenu,
|
||||
}),
|
||||
}));
|
||||
|
||||
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'workflow',
|
||||
)!;
|
||||
|
||||
jest.mock('@/object-metadata/hooks/useObjectMetadataItem', () => ({
|
||||
useObjectMetadataItem: jest.fn(() => ({
|
||||
objectMetadataItem: workflowMockObjectMetadataItem,
|
||||
})),
|
||||
}));
|
||||
|
||||
const wrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
||||
apolloMocks: [],
|
||||
componentInstanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
contextStoreCurrentObjectMetadataNameSingular:
|
||||
workflowMockObjectMetadataItem.nameSingular,
|
||||
contextStoreCurrentViewId: 'my-view-id',
|
||||
contextStoreTargetedRecordsRule: {
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
contextStoreNumberOfSelectedRecords: 0,
|
||||
contextStoreCurrentViewType: ContextStoreViewType.Table,
|
||||
});
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const {
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
openStepSelectInCommandMenu,
|
||||
openWorkflowEditStepInCommandMenu,
|
||||
openWorkflowViewStepInCommandMenu,
|
||||
} = useWorkflowCommandMenu();
|
||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||
const commandMenuNavigationMorphItemByPage = useRecoilValue(
|
||||
commandMenuNavigationMorphItemByPageState,
|
||||
);
|
||||
|
||||
const viewableRecordId = useRecoilComponentValueV2(
|
||||
viewableRecordIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const viewableRecordNameSingular = useRecoilComponentValueV2(
|
||||
viewableRecordNameSingularComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const currentObjectMetadataItemId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const targetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const numberOfSelectedRecords = useRecoilComponentValueV2(
|
||||
contextStoreNumberOfSelectedRecordsComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const currentViewType = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewTypeComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const workflowId = useRecoilComponentValueV2(
|
||||
workflowIdComponentState,
|
||||
'mocked-uuid',
|
||||
);
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
return {
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
openStepSelectInCommandMenu,
|
||||
openWorkflowEditStepInCommandMenu,
|
||||
openWorkflowViewStepInCommandMenu,
|
||||
workflowId,
|
||||
viewableRecordId,
|
||||
commandMenuPage,
|
||||
commandMenuNavigationMorphItemByPage,
|
||||
viewableRecordNameSingular,
|
||||
currentObjectMetadataItemId,
|
||||
targetedRecordsRule,
|
||||
numberOfSelectedRecords,
|
||||
currentViewType,
|
||||
getIcon,
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper,
|
||||
},
|
||||
);
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useWorkflowCommandMenu', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should navigate to the workflow step select trigger type page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.openWorkflowTriggerTypeInCommandMenu('test-workflow-id');
|
||||
});
|
||||
|
||||
expect(result.current.workflowId).toBe('test-workflow-id');
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.WorkflowStepSelectTriggerType,
|
||||
pageTitle: t`Trigger Type`,
|
||||
pageIcon: IconBolt,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to the workflow step select action page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.openStepSelectInCommandMenu('test-workflow-id');
|
||||
});
|
||||
|
||||
expect(result.current.workflowId).toBe('test-workflow-id');
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.WorkflowStepSelectAction,
|
||||
pageTitle: t`Select Action`,
|
||||
pageIcon: IconSettingsAutomation,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to the workflow step edit page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.openWorkflowEditStepInCommandMenu(
|
||||
'test-workflow-id',
|
||||
'Edit Step',
|
||||
IconSettingsAutomation,
|
||||
);
|
||||
});
|
||||
|
||||
expect(result.current.workflowId).toBe('test-workflow-id');
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.WorkflowStepEdit,
|
||||
pageTitle: 'Edit Step',
|
||||
pageIcon: IconSettingsAutomation,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to the workflow step view page', () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
act(() => {
|
||||
result.current.openWorkflowViewStepInCommandMenu(
|
||||
'test-workflow-id',
|
||||
'View Step',
|
||||
IconSettingsAutomation,
|
||||
);
|
||||
});
|
||||
|
||||
expect(result.current.workflowId).toBe('test-workflow-id');
|
||||
|
||||
expect(mockNavigateCommandMenu).toHaveBeenCalledWith({
|
||||
page: CommandMenuPages.WorkflowStepView,
|
||||
pageTitle: 'View Step',
|
||||
pageIcon: IconSettingsAutomation,
|
||||
pageId: 'mocked-uuid',
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,79 +1,17 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import {
|
||||
IconBolt,
|
||||
IconCalendarEvent,
|
||||
IconComponent,
|
||||
IconDotsVertical,
|
||||
IconMail,
|
||||
IconSearch,
|
||||
IconSettingsAutomation,
|
||||
useIcons,
|
||||
} from 'twenty-ui';
|
||||
import { IconDotsVertical } from 'twenty-ui';
|
||||
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId';
|
||||
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
|
||||
import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndActionMenuStates';
|
||||
import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
||||
import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { capitalize, isDefined } from 'twenty-shared';
|
||||
import { v4 } from 'uuid';
|
||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||
|
||||
export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
pageTitle: string;
|
||||
pageIcon: IconComponent;
|
||||
pageIconColor?: string;
|
||||
pageId?: string;
|
||||
};
|
||||
|
||||
export const useCommandMenu = () => {
|
||||
const { resetSelectedItem } = useSelectableList('command-menu-list');
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
const { resetContextStoreStates } = useResetContextStoreStates();
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
|
||||
const theme = useTheme();
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const closeCommandMenu = useRecoilCallback(
|
||||
({ set }) =>
|
||||
@ -85,141 +23,7 @@ export const useCommandMenu = () => {
|
||||
[],
|
||||
);
|
||||
|
||||
const onCommandMenuCloseAnimationComplete = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
|
||||
|
||||
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
|
||||
|
||||
set(viewableRecordIdState, null);
|
||||
set(commandMenuPageState, CommandMenuPages.Root);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
set(isCommandMenuOpenedState, false);
|
||||
set(commandMenuSearchState, '');
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationStackState, []);
|
||||
resetSelectedItem();
|
||||
set(hasUserSelectedCommandState, false);
|
||||
goBackToPreviousHotkeyScope();
|
||||
|
||||
emitRightDrawerCloseEvent();
|
||||
set(isCommandMenuClosingState, false);
|
||||
},
|
||||
[
|
||||
closeDropdown,
|
||||
goBackToPreviousHotkeyScope,
|
||||
resetContextStoreStates,
|
||||
resetSelectedItem,
|
||||
],
|
||||
);
|
||||
|
||||
const openCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
const isCommandMenuOpened = snapshot
|
||||
.getLoadable(isCommandMenuOpenedState)
|
||||
.getValue();
|
||||
|
||||
const isCommandMenuClosing = snapshot
|
||||
.getLoadable(isCommandMenuClosingState)
|
||||
.getValue();
|
||||
|
||||
if (isCommandMenuClosing) {
|
||||
onCommandMenuCloseAnimationComplete();
|
||||
}
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
||||
|
||||
if (isCommandMenuOpened) {
|
||||
return;
|
||||
}
|
||||
|
||||
copyContextStoreStates({
|
||||
instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
set(isCommandMenuOpenedState, true);
|
||||
set(hasUserSelectedCommandState, false);
|
||||
set(isDragSelectionStartEnabledState, false);
|
||||
},
|
||||
[
|
||||
copyContextStoreStates,
|
||||
onCommandMenuCloseAnimationComplete,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
],
|
||||
);
|
||||
|
||||
const navigateCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) => {
|
||||
return ({
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
resetNavigationStack = false,
|
||||
}: CommandMenuNavigationStackItem & {
|
||||
resetNavigationStack?: boolean;
|
||||
}) => {
|
||||
if (!pageId) {
|
||||
pageId = v4();
|
||||
}
|
||||
|
||||
openCommandMenu();
|
||||
set(commandMenuPageState, page);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: pageTitle,
|
||||
Icon: pageIcon,
|
||||
instanceId: pageId,
|
||||
});
|
||||
|
||||
const isCommandMenuClosing = snapshot
|
||||
.getLoadable(isCommandMenuClosingState)
|
||||
.getValue();
|
||||
|
||||
const currentNavigationStack = isCommandMenuClosing
|
||||
? []
|
||||
: snapshot.getLoadable(commandMenuNavigationStackState).getValue();
|
||||
|
||||
if (resetNavigationStack) {
|
||||
set(commandMenuNavigationStackState, [
|
||||
{
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
},
|
||||
]);
|
||||
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
} else {
|
||||
set(commandMenuNavigationStackState, [
|
||||
...currentNavigationStack,
|
||||
{
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
},
|
||||
]);
|
||||
}
|
||||
};
|
||||
},
|
||||
[openCommandMenu],
|
||||
);
|
||||
|
||||
const openRootCommandMenu = useCallback(() => {
|
||||
const openCommandMenu = useCallback(() => {
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.Root,
|
||||
pageTitle: 'Command Menu',
|
||||
@ -240,503 +44,16 @@ export const useCommandMenu = () => {
|
||||
if (isCommandMenuOpened) {
|
||||
closeCommandMenu();
|
||||
} else {
|
||||
openRootCommandMenu();
|
||||
openCommandMenu();
|
||||
}
|
||||
},
|
||||
[closeCommandMenu, openRootCommandMenu],
|
||||
);
|
||||
|
||||
const goBackFromCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) => {
|
||||
return () => {
|
||||
const currentNavigationStack = snapshot
|
||||
.getLoadable(commandMenuNavigationStackState)
|
||||
.getValue();
|
||||
|
||||
const newNavigationStack = currentNavigationStack.slice(0, -1);
|
||||
const lastNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(lastNavigationStackItem)) {
|
||||
closeCommandMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
set(commandMenuPageState, lastNavigationStackItem.page);
|
||||
|
||||
set(commandMenuPageInfoState, {
|
||||
title: lastNavigationStackItem.pageTitle,
|
||||
Icon: lastNavigationStackItem.pageIcon,
|
||||
instanceId: lastNavigationStackItem.pageId,
|
||||
});
|
||||
|
||||
set(commandMenuNavigationStackState, newNavigationStack);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
if (currentNavigationStack.length > 0) {
|
||||
const removedItem = currentNavigationStack.at(-1);
|
||||
|
||||
if (isDefined(removedItem)) {
|
||||
const newMorphItems = new Map(currentMorphItems);
|
||||
newMorphItems.delete(removedItem.pageId);
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
}
|
||||
}
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
},
|
||||
[closeCommandMenu],
|
||||
);
|
||||
|
||||
const navigateCommandMenuHistory = useRecoilCallback(({ snapshot, set }) => {
|
||||
return (pageIndex: number) => {
|
||||
const currentNavigationStack = snapshot
|
||||
.getLoadable(commandMenuNavigationStackState)
|
||||
.getValue();
|
||||
|
||||
const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1);
|
||||
|
||||
set(commandMenuNavigationStackState, newNavigationStack);
|
||||
|
||||
const newNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(newNavigationStackItem)) {
|
||||
throw new Error(
|
||||
`No command menu navigation stack item found for index ${pageIndex}`,
|
||||
);
|
||||
}
|
||||
|
||||
set(commandMenuPageState, newNavigationStackItem?.page);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: newNavigationStackItem?.pageTitle,
|
||||
Icon: newNavigationStackItem?.pageIcon,
|
||||
instanceId: newNavigationStackItem?.pageId,
|
||||
});
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const newMorphItems = new Map(
|
||||
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
||||
newNavigationStack.some((item) => item.pageId === pageId),
|
||||
),
|
||||
);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const openRecordInCommandMenu = useRecoilCallback(
|
||||
({ set, snapshot }) => {
|
||||
return ({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
isNewRecord = false,
|
||||
}: {
|
||||
recordId: string;
|
||||
objectNameSingular: string;
|
||||
isNewRecord?: boolean;
|
||||
}) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordNameSingularComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectNameSingular,
|
||||
);
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
recordId,
|
||||
);
|
||||
set(viewableRecordIdState, recordId);
|
||||
|
||||
const objectMetadataItem = snapshot
|
||||
.getLoadable(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectName: objectNameSingular,
|
||||
objectNameType: 'singular',
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!objectMetadataItem) {
|
||||
throw new Error(
|
||||
`No object metadata item found for object name ${objectNameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectMetadataItem.id,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [recordId],
|
||||
},
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
1,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
ContextStoreViewType.ShowPage,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
snapshot
|
||||
.getLoadable(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}),
|
||||
)
|
||||
.getValue(),
|
||||
);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const morphItemToAdd = {
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
recordId,
|
||||
};
|
||||
|
||||
const newMorphItems = new Map([
|
||||
...currentMorphItems,
|
||||
[pageComponentInstanceId, morphItemToAdd],
|
||||
]);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
const Icon = objectMetadataItem?.icon
|
||||
? getIcon(objectMetadataItem.icon)
|
||||
: getIcon('IconList');
|
||||
|
||||
const IconColor = getIconColorForObjectType({
|
||||
objectType: objectMetadataItem.nameSingular,
|
||||
theme,
|
||||
});
|
||||
|
||||
const capitalizedObjectNameSingular = capitalize(objectNameSingular);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: isNewRecord
|
||||
? t`New ${capitalizedObjectNameSingular}`
|
||||
: capitalizedObjectNameSingular,
|
||||
pageIcon: Icon,
|
||||
pageIconColor: IconColor,
|
||||
pageId: pageComponentInstanceId,
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
};
|
||||
},
|
||||
[getIcon, navigateCommandMenu, theme],
|
||||
);
|
||||
|
||||
const openWorkflowTriggerTypeInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepSelectTriggerType,
|
||||
pageTitle: t`Trigger Type`,
|
||||
pageIcon: IconBolt,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowActionInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepSelectAction,
|
||||
pageTitle: t`Select Action`,
|
||||
pageIcon: IconSettingsAutomation,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowEditStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepEdit,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowViewStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepView,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowViewRunStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowRunStepView,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openRecordsSearchPage = () => {
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: 'Search',
|
||||
pageIcon: IconSearch,
|
||||
pageId: v4(),
|
||||
});
|
||||
};
|
||||
|
||||
const openCalendarEventInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (calendarEventId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
calendarEventId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to calendar event title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.CalendarEvent,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: calendarEventId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewCalendarEvent,
|
||||
pageTitle: 'Calendar Event',
|
||||
pageIcon: IconCalendarEvent,
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openEmailThreadInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (emailThreadId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
emailThreadId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to show the thread title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.MessageThread,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: emailThreadId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewEmailThread,
|
||||
pageTitle: 'Email Thread',
|
||||
pageIcon: IconMail,
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const setGlobalCommandMenuContext = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return () => {
|
||||
copyContextStoreStates({
|
||||
instanceIdToCopyFrom: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
ContextStoreViewType.Table,
|
||||
);
|
||||
|
||||
set(commandMenuPageInfoState, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
},
|
||||
[copyContextStoreStates],
|
||||
[closeCommandMenu, openCommandMenu],
|
||||
);
|
||||
|
||||
return {
|
||||
openRootCommandMenu,
|
||||
openCommandMenu,
|
||||
closeCommandMenu,
|
||||
onCommandMenuCloseAnimationComplete,
|
||||
navigateCommandMenu,
|
||||
navigateCommandMenuHistory,
|
||||
goBackFromCommandMenu,
|
||||
openRecordsSearchPage,
|
||||
openRecordInCommandMenu,
|
||||
toggleCommandMenu,
|
||||
setGlobalCommandMenuContext,
|
||||
openCalendarEventInCommandMenu,
|
||||
openEmailThreadInCommandMenu,
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
openWorkflowActionInCommandMenu,
|
||||
openWorkflowEditStepInCommandMenu,
|
||||
openWorkflowViewStepInCommandMenu,
|
||||
openWorkflowViewRunStepInCommandMenu,
|
||||
};
|
||||
};
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID } from '@/command-menu/constants/CommandMenuContextChipGroupsDropdownId';
|
||||
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
|
||||
import { useResetContextStoreStates } from '@/command-menu/hooks/useResetContextStoreStates';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
const { resetSelectedItem } = useSelectableList('command-menu-list');
|
||||
|
||||
const { goBackToPreviousHotkeyScope } = usePreviousHotkeyScope();
|
||||
|
||||
const { resetContextStoreStates } = useResetContextStoreStates();
|
||||
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
|
||||
const commandMenuCloseAnimationCompleteCleanup = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
closeDropdown(COMMAND_MENU_CONTEXT_CHIP_GROUPS_DROPDOWN_ID);
|
||||
|
||||
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
|
||||
|
||||
set(viewableRecordIdState, null);
|
||||
set(commandMenuPageState, CommandMenuPages.Root);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
set(isCommandMenuOpenedState, false);
|
||||
set(commandMenuSearchState, '');
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationStackState, []);
|
||||
resetSelectedItem();
|
||||
set(hasUserSelectedCommandState, false);
|
||||
goBackToPreviousHotkeyScope();
|
||||
|
||||
emitRightDrawerCloseEvent();
|
||||
set(isCommandMenuClosingState, false);
|
||||
},
|
||||
[
|
||||
closeDropdown,
|
||||
goBackToPreviousHotkeyScope,
|
||||
resetContextStoreStates,
|
||||
resetSelectedItem,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
};
|
||||
};
|
||||
@ -1,5 +1,5 @@
|
||||
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistory';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
@ -24,7 +24,7 @@ export const useCommandMenuContextChips = () => {
|
||||
commandMenuNavigationStackState,
|
||||
);
|
||||
|
||||
const { navigateCommandMenuHistory } = useCommandMenu();
|
||||
const { navigateCommandMenuHistory } = useCommandMenuHistory();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useCommandMenuHistory = () => {
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const goBackFromCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) => {
|
||||
return () => {
|
||||
const currentNavigationStack = snapshot
|
||||
.getLoadable(commandMenuNavigationStackState)
|
||||
.getValue();
|
||||
|
||||
const newNavigationStack = currentNavigationStack.slice(0, -1);
|
||||
const lastNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(lastNavigationStackItem)) {
|
||||
closeCommandMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
set(commandMenuPageState, lastNavigationStackItem.page);
|
||||
|
||||
set(commandMenuPageInfoState, {
|
||||
title: lastNavigationStackItem.pageTitle,
|
||||
Icon: lastNavigationStackItem.pageIcon,
|
||||
instanceId: lastNavigationStackItem.pageId,
|
||||
});
|
||||
|
||||
set(commandMenuNavigationStackState, newNavigationStack);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
if (currentNavigationStack.length > 0) {
|
||||
const removedItem = currentNavigationStack.at(-1);
|
||||
|
||||
if (isDefined(removedItem)) {
|
||||
const newMorphItems = new Map(currentMorphItems);
|
||||
newMorphItems.delete(removedItem.pageId);
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
}
|
||||
}
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
},
|
||||
[closeCommandMenu],
|
||||
);
|
||||
|
||||
const navigateCommandMenuHistory = useRecoilCallback(({ snapshot, set }) => {
|
||||
return (pageIndex: number) => {
|
||||
const currentNavigationStack = snapshot
|
||||
.getLoadable(commandMenuNavigationStackState)
|
||||
.getValue();
|
||||
|
||||
const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1);
|
||||
|
||||
set(commandMenuNavigationStackState, newNavigationStack);
|
||||
|
||||
const newNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(newNavigationStackItem)) {
|
||||
throw new Error(
|
||||
`No command menu navigation stack item found for index ${pageIndex}`,
|
||||
);
|
||||
}
|
||||
|
||||
set(commandMenuPageState, newNavigationStackItem.page);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: newNavigationStackItem.pageTitle,
|
||||
Icon: newNavigationStackItem.pageIcon,
|
||||
instanceId: newNavigationStackItem.pageId,
|
||||
});
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const newMorphItems = new Map(
|
||||
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
||||
newNavigationStack.some((item) => item.pageId === pageId),
|
||||
),
|
||||
);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
goBackFromCommandMenu,
|
||||
navigateCommandMenuHistory,
|
||||
};
|
||||
};
|
||||
@ -1,5 +1,8 @@
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useCommandMenuHistory } from '@/command-menu/hooks/useCommandMenuHistory';
|
||||
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
||||
import { useSetGlobalCommandMenuContext } from '@/command-menu/hooks/useSetGlobalCommandMenuContext';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
@ -13,12 +16,13 @@ import { useRecoilValue } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
export const useCommandMenuHotKeys = () => {
|
||||
const {
|
||||
openRecordsSearchPage,
|
||||
toggleCommandMenu,
|
||||
goBackFromCommandMenu,
|
||||
setGlobalCommandMenuContext,
|
||||
} = useCommandMenu();
|
||||
const { toggleCommandMenu } = useCommandMenu();
|
||||
|
||||
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
||||
|
||||
const { goBackFromCommandMenu } = useCommandMenuHistory();
|
||||
|
||||
const { setGlobalCommandMenuContext } = useSetGlobalCommandMenuContext();
|
||||
|
||||
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
|
||||
|
||||
|
||||
@ -0,0 +1,137 @@
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { useCommandMenuCloseAnimationCompleteCleanup } from '@/command-menu/hooks/useCommandMenuCloseAnimationCompleteCleanup';
|
||||
import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndActionMenuStates';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { commandMenuNavigationRecordsState } from '@/command-menu/states/commandMenuNavigationRecordsState';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { isCommandMenuClosingState } from '@/command-menu/states/isCommandMenuClosingState';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { isDragSelectionStartEnabledState } from '@/ui/utilities/drag-select/states/internal/isDragSelectionStartEnabledState';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconComponent } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
pageTitle: string;
|
||||
pageIcon: IconComponent;
|
||||
pageIconColor?: string;
|
||||
pageId?: string;
|
||||
};
|
||||
|
||||
export const useNavigateCommandMenu = () => {
|
||||
const { setHotkeyScopeAndMemorizePreviousScope } = usePreviousHotkeyScope();
|
||||
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
useCommandMenuCloseAnimationCompleteCleanup();
|
||||
|
||||
const openCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
const isCommandMenuOpened = snapshot
|
||||
.getLoadable(isCommandMenuOpenedState)
|
||||
.getValue();
|
||||
|
||||
const isCommandMenuClosing = snapshot
|
||||
.getLoadable(isCommandMenuClosingState)
|
||||
.getValue();
|
||||
|
||||
if (isCommandMenuClosing) {
|
||||
commandMenuCloseAnimationCompleteCleanup();
|
||||
}
|
||||
|
||||
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenuOpen);
|
||||
|
||||
if (isCommandMenuOpened) {
|
||||
return;
|
||||
}
|
||||
|
||||
copyContextStoreStates({
|
||||
instanceIdToCopyFrom: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
set(isCommandMenuOpenedState, true);
|
||||
set(hasUserSelectedCommandState, false);
|
||||
set(isDragSelectionStartEnabledState, false);
|
||||
},
|
||||
[
|
||||
copyContextStoreStates,
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
],
|
||||
);
|
||||
|
||||
const navigateCommandMenu = useRecoilCallback(
|
||||
({ snapshot, set }) => {
|
||||
return ({
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId,
|
||||
resetNavigationStack = false,
|
||||
}: CommandMenuNavigationStackItem & {
|
||||
resetNavigationStack?: boolean;
|
||||
}) => {
|
||||
const computedPageId = pageId || v4();
|
||||
|
||||
openCommandMenu();
|
||||
set(commandMenuPageState, page);
|
||||
set(commandMenuPageInfoState, {
|
||||
title: pageTitle,
|
||||
Icon: pageIcon,
|
||||
instanceId: computedPageId,
|
||||
});
|
||||
|
||||
const isCommandMenuClosing = snapshot
|
||||
.getLoadable(isCommandMenuClosingState)
|
||||
.getValue();
|
||||
|
||||
const currentNavigationStack = isCommandMenuClosing
|
||||
? []
|
||||
: snapshot.getLoadable(commandMenuNavigationStackState).getValue();
|
||||
|
||||
if (resetNavigationStack) {
|
||||
set(commandMenuNavigationStackState, [
|
||||
{
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId: computedPageId,
|
||||
},
|
||||
]);
|
||||
|
||||
set(commandMenuNavigationRecordsState, []);
|
||||
set(commandMenuNavigationMorphItemByPageState, new Map());
|
||||
} else {
|
||||
set(commandMenuNavigationStackState, [
|
||||
...currentNavigationStack,
|
||||
{
|
||||
page,
|
||||
pageTitle,
|
||||
pageIcon,
|
||||
pageIconColor,
|
||||
pageId: computedPageId,
|
||||
},
|
||||
]);
|
||||
}
|
||||
};
|
||||
},
|
||||
[openCommandMenu],
|
||||
);
|
||||
|
||||
return {
|
||||
navigateCommandMenu,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,63 @@
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconCalendarEvent } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useOpenCalendarEventInCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const openCalendarEventInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (calendarEventId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
calendarEventId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to calendar event title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.CalendarEvent,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: calendarEventId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewCalendarEvent,
|
||||
pageTitle: t`Calendar Event`,
|
||||
pageIcon: IconCalendarEvent,
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
return {
|
||||
openCalendarEventInCommandMenu,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,62 @@
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconMail } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useOpenEmailThreadInCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const openEmailThreadInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (emailThreadId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
emailThreadId,
|
||||
);
|
||||
|
||||
// TODO: Uncomment this once we need to show the thread title in the navigation
|
||||
// const objectMetadataItem = snapshot
|
||||
// .getLoadable(objectMetadataItemsState)
|
||||
// .getValue()
|
||||
// .find(
|
||||
// ({ nameSingular }) =>
|
||||
// nameSingular === CoreObjectNameSingular.MessageThread,
|
||||
// );
|
||||
|
||||
// set(
|
||||
// commandMenuNavigationMorphItemsState,
|
||||
// new Map([
|
||||
// ...snapshot
|
||||
// .getLoadable(commandMenuNavigationMorphItemsState)
|
||||
// .getValue(),
|
||||
// [
|
||||
// pageComponentInstanceId,
|
||||
// {
|
||||
// objectMetadataId: objectMetadataItem?.id,
|
||||
// recordId: emailThreadId,
|
||||
// },
|
||||
// ],
|
||||
// ]),
|
||||
// );
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewEmailThread,
|
||||
pageTitle: 'Email Thread',
|
||||
pageIcon: IconMail,
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
return {
|
||||
openEmailThreadInCommandMenu,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,158 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { viewableRecordNameSingularComponentState } from '@/command-menu/pages/record-page/states/viewableRecordNameSingularComponentState';
|
||||
import { commandMenuNavigationMorphItemByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { capitalize } from 'twenty-shared';
|
||||
import { useIcons } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useOpenRecordInCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useCommandMenu();
|
||||
|
||||
const theme = useTheme();
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
const openRecordInCommandMenu = useRecoilCallback(
|
||||
({ set, snapshot }) => {
|
||||
return ({
|
||||
recordId,
|
||||
objectNameSingular,
|
||||
isNewRecord = false,
|
||||
}: {
|
||||
recordId: string;
|
||||
objectNameSingular: string;
|
||||
isNewRecord?: boolean;
|
||||
}) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
set(
|
||||
viewableRecordNameSingularComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectNameSingular,
|
||||
);
|
||||
set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
recordId,
|
||||
);
|
||||
set(viewableRecordIdState, recordId);
|
||||
|
||||
const objectMetadataItem = snapshot
|
||||
.getLoadable(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectName: objectNameSingular,
|
||||
objectNameType: 'singular',
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!objectMetadataItem) {
|
||||
throw new Error(
|
||||
`No object metadata item found for object name ${objectNameSingular}`,
|
||||
);
|
||||
}
|
||||
|
||||
set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectMetadataItem.id,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [recordId],
|
||||
},
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
1,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
ContextStoreViewType.ShowPage,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
snapshot
|
||||
.getLoadable(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}),
|
||||
)
|
||||
.getValue(),
|
||||
);
|
||||
|
||||
const currentMorphItems = snapshot
|
||||
.getLoadable(commandMenuNavigationMorphItemByPageState)
|
||||
.getValue();
|
||||
|
||||
const morphItemToAdd = {
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
recordId,
|
||||
};
|
||||
|
||||
const newMorphItems = new Map(currentMorphItems);
|
||||
newMorphItems.set(pageComponentInstanceId, morphItemToAdd);
|
||||
|
||||
set(commandMenuNavigationMorphItemByPageState, newMorphItems);
|
||||
|
||||
const Icon = objectMetadataItem?.icon
|
||||
? getIcon(objectMetadataItem.icon)
|
||||
: getIcon('IconList');
|
||||
|
||||
const IconColor = getIconColorForObjectType({
|
||||
objectType: objectMetadataItem.nameSingular,
|
||||
theme,
|
||||
});
|
||||
|
||||
const capitalizedObjectNameSingular = capitalize(objectNameSingular);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.ViewRecord,
|
||||
pageTitle: isNewRecord
|
||||
? t`New ${capitalizedObjectNameSingular}`
|
||||
: capitalizedObjectNameSingular,
|
||||
pageIcon: Icon,
|
||||
pageIconColor: IconColor,
|
||||
pageId: pageComponentInstanceId,
|
||||
resetNavigationStack: false,
|
||||
});
|
||||
};
|
||||
},
|
||||
[getIcon, navigateCommandMenu, theme],
|
||||
);
|
||||
|
||||
return {
|
||||
openRecordInCommandMenu,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,22 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconSearch } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useOpenRecordsSearchPageInCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useCommandMenu();
|
||||
|
||||
const openRecordsSearchPage = () => {
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.SearchRecords,
|
||||
pageTitle: t`Search`,
|
||||
pageIcon: IconSearch,
|
||||
pageId: v4(),
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
openRecordsSearchPage,
|
||||
};
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { t } from '@lingui/core/macro';
|
||||
@ -24,7 +24,7 @@ export const useSearchRecords = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const commands = useMemo(() => {
|
||||
return (globalSearchData?.globalSearch ?? []).map((searchRecord) => {
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId';
|
||||
import { COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuPreviousComponentInstanceId';
|
||||
import { useCopyContextStoreStates } from '@/command-menu/hooks/useCopyContextStoreAndActionMenuStates';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useSetGlobalCommandMenuContext = () => {
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
|
||||
const setGlobalCommandMenuContext = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return () => {
|
||||
copyContextStoreStates({
|
||||
instanceIdToCopyFrom: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
ContextStoreViewType.Table,
|
||||
);
|
||||
|
||||
set(commandMenuPageInfoState, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
|
||||
set(hasUserSelectedCommandState, false);
|
||||
};
|
||||
},
|
||||
[copyContextStoreStates],
|
||||
);
|
||||
|
||||
return {
|
||||
setGlobalCommandMenuContext,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,124 @@
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { workflowIdComponentState } from '@/command-menu/pages/workflow/states/workflowIdComponentState';
|
||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { IconBolt, IconComponent, IconSettingsAutomation } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const useWorkflowCommandMenu = () => {
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const openWorkflowTriggerTypeInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepSelectTriggerType,
|
||||
pageTitle: t`Trigger Type`,
|
||||
pageIcon: IconBolt,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openStepSelectInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepSelectAction,
|
||||
pageTitle: t`Select Action`,
|
||||
pageIcon: IconSettingsAutomation,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowEditStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepEdit,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowViewStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowStepView,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
const openWorkflowRunViewStepInCommandMenu = useRecoilCallback(
|
||||
({ set }) => {
|
||||
return (workflowId: string, title: string, icon: IconComponent) => {
|
||||
const pageId = v4();
|
||||
|
||||
set(
|
||||
workflowIdComponentState.atomFamily({ instanceId: pageId }),
|
||||
workflowId,
|
||||
);
|
||||
|
||||
navigateCommandMenu({
|
||||
page: CommandMenuPages.WorkflowRunStepView,
|
||||
pageTitle: title,
|
||||
pageIcon: icon,
|
||||
pageId,
|
||||
});
|
||||
};
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
);
|
||||
|
||||
return {
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
openStepSelectInCommandMenu,
|
||||
openWorkflowEditStepInCommandMenu,
|
||||
openWorkflowViewStepInCommandMenu,
|
||||
openWorkflowRunViewStepInCommandMenu,
|
||||
};
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import {
|
||||
WorkflowTriggerType,
|
||||
@ -26,7 +26,7 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({
|
||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
const { openWorkflowEditStepInCommandMenu } = useCommandMenu();
|
||||
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const handleTriggerTypeClick = ({
|
||||
type,
|
||||
|
||||
@ -2,7 +2,7 @@ import { useLocation } from 'react-router-dom';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { IconSearch, IconSettings } from 'twenty-ui';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
||||
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
||||
import { WorkspaceFavorites } from '@/favorites/components/WorkspaceFavorites';
|
||||
import { NavigationDrawerOpenedSection } from '@/object-metadata/components/NavigationDrawerOpenedSection';
|
||||
@ -41,7 +41,7 @@ export const MainNavigationDrawerItems = () => {
|
||||
|
||||
const { t } = useLingui();
|
||||
|
||||
const { openRecordsSearchPage } = useCommandMenu();
|
||||
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { useOpenSettingsMenu } from '@/navigation/hooks/useOpenSettings';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
@ -17,7 +18,8 @@ type NavigationBarItemName = 'main' | 'search' | 'tasks' | 'settings';
|
||||
|
||||
export const MobileNavigationBar = () => {
|
||||
const [isCommandMenuOpened] = useRecoilState(isCommandMenuOpenedState);
|
||||
const { closeCommandMenu, openRecordsSearchPage } = useCommandMenu();
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useRecoilState(isNavigationDrawerExpandedState);
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
isModifiedEvent,
|
||||
} from 'twenty-ui';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { getLinkToShowPage } from '@/object-metadata/utils/getLinkToShowPage';
|
||||
import { useRecordChipData } from '@/object-record/hooks/useRecordChipData';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
@ -39,7 +39,7 @@ export const RecordChip = ({
|
||||
record,
|
||||
});
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const recordIndexOpenRecordIn = useRecoilValue(recordIndexOpenRecordInState);
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
|
||||
import { getActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getActionMenuDropdownIdFromActionMenuId';
|
||||
import { getActionMenuIdFromRecordIndexId } from '@/action-menu/utils/getActionMenuIdFromRecordIndexId';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
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 { isRecordBoardCardSelectedComponentFamilyState } from '@/object-record/record-board/states/isRecordBoardCardSelectedComponentFamilyState';
|
||||
import { isRecordBoardCompactModeActiveComponentState } from '@/object-record/record-board/states/isRecordBoardCompactModeActiveComponentState';
|
||||
import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector';
|
||||
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
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 { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
@ -81,7 +81,7 @@ export const RecordBoardCard = ({
|
||||
position?: 'first' | 'last';
|
||||
}) => {
|
||||
const navigate = useNavigateApp();
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const { recordId } = useContext(RecordBoardCardContext);
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useAddNewCard } from '@/object-record/record-board/record-board-column/hooks/useAddNewCard';
|
||||
@ -38,7 +38,7 @@ export const RecordBoardColumnNewOpportunity = ({
|
||||
viewableRecordNameSingularState,
|
||||
);
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const createCompanyOpportunityAndOpenCommandMenu = async (
|
||||
searchInput?: string,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
|
||||
@ -42,7 +42,7 @@ export const useAddNewRecordAndOpenRightDrawer = ({
|
||||
.nameSingular ?? 'workspaceMember',
|
||||
});
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
if (
|
||||
relationObjectMetadataNameSingular === 'workspaceMember' ||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
@ -39,7 +39,7 @@ export const useCreateNewTableRecord = ({
|
||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const { createOneRecord } = useCreateOneRecord({
|
||||
objectNameSingular: objectMetadataItem.nameSingular,
|
||||
|
||||
@ -17,7 +17,7 @@ import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useC
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
|
||||
import { useOpenFieldInputEditMode } from '@/object-record/record-field/hooks/useOpenFieldInputEditMode';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { recordIndexOpenRecordInState } from '@/object-record/record-index/states/recordIndexOpenRecordInState';
|
||||
@ -75,7 +75,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
||||
const { setActiveDropdownFocusIdAndMemorizePrevious } =
|
||||
useSetActiveDropdownFocusIdAndMemorizePrevious();
|
||||
|
||||
const { openRecordInCommandMenu } = useCommandMenu();
|
||||
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();
|
||||
|
||||
const { openFieldInput } = useOpenFieldInputEditMode();
|
||||
|
||||
|
||||
@ -2,9 +2,9 @@ import { useCallback, useContext } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { EMPTY_TRIGGER_STEP_ID } from '@/workflow/workflow-diagram/constants/EmptyTriggerStepId';
|
||||
import { useStartNodeCreation } from '@/workflow/workflow-diagram/hooks/useStartNodeCreation';
|
||||
@ -27,7 +27,7 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
||||
const {
|
||||
openWorkflowTriggerTypeInCommandMenu,
|
||||
openWorkflowEditStepInCommandMenu,
|
||||
} = useCommandMenu();
|
||||
} = useWorkflowCommandMenu();
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { useTriggerNodeSelection } from '@/workflow/workflow-diagram/hooks/useTriggerNodeSelection';
|
||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
||||
@ -16,7 +16,7 @@ import { useIcons } from 'twenty-ui';
|
||||
export const WorkflowDiagramCanvasReadonlyEffect = () => {
|
||||
const { getIcon } = useIcons();
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
const { openWorkflowViewStepInCommandMenu } = useCommandMenu();
|
||||
const { openWorkflowViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { useTabListStates } from '@/ui/layout/tab/hooks/internal/useTabListStates';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
@ -20,7 +20,7 @@ import { useIcons } from 'twenty-ui';
|
||||
export const WorkflowRunDiagramCanvasEffect = () => {
|
||||
const { getIcon } = useIcons();
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
const { openWorkflowViewRunStepInCommandMenu } = useCommandMenu();
|
||||
const { openWorkflowRunViewStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
|
||||
@ -68,7 +68,7 @@ export const WorkflowRunDiagramCanvasEffect = () => {
|
||||
}
|
||||
|
||||
if (isDefined(workflowId)) {
|
||||
openWorkflowViewRunStepInCommandMenu(
|
||||
openWorkflowRunViewStepInCommandMenu(
|
||||
workflowId,
|
||||
selectedNodeData.name,
|
||||
getIcon(getWorkflowNodeIconKey(selectedNodeData)),
|
||||
@ -80,7 +80,7 @@ export const WorkflowRunDiagramCanvasEffect = () => {
|
||||
workflowId,
|
||||
getIcon,
|
||||
goBackToFirstWorkflowRunRightDrawerTabIfNeeded,
|
||||
openWorkflowViewRunStepInCommandMenu,
|
||||
openWorkflowRunViewStepInCommandMenu,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { workflowIdState } from '@/workflow/states/workflowIdState';
|
||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -10,7 +10,7 @@ export const useStartNodeCreation = () => {
|
||||
const setWorkflowCreateStepFromParentStepId = useSetRecoilState(
|
||||
workflowCreateStepFromParentStepIdState,
|
||||
);
|
||||
const { openWorkflowActionInCommandMenu } = useCommandMenu();
|
||||
const { openStepSelectInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
|
||||
@ -23,14 +23,14 @@ export const useStartNodeCreation = () => {
|
||||
setWorkflowCreateStepFromParentStepId(parentNodeId);
|
||||
|
||||
if (isDefined(workflowId)) {
|
||||
openWorkflowActionInCommandMenu(workflowId);
|
||||
openStepSelectInCommandMenu(workflowId);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[
|
||||
setWorkflowCreateStepFromParentStepId,
|
||||
workflowId,
|
||||
openWorkflowActionInCommandMenu,
|
||||
openStepSelectInCommandMenu,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { useWorkflowCommandMenu } from '@/command-menu/hooks/useWorkflowCommandMenu';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import {
|
||||
WorkflowTriggerType,
|
||||
@ -26,7 +26,7 @@ export const RightDrawerWorkflowSelectTriggerTypeContent = ({
|
||||
const { activeObjectMetadataItems } = useFilteredObjectMetadataItems();
|
||||
|
||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||
const { openWorkflowEditStepInCommandMenu } = useCommandMenu();
|
||||
const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu();
|
||||
|
||||
const handleTriggerTypeClick = ({
|
||||
type,
|
||||
|
||||
@ -2,12 +2,14 @@ import { PropsWithChildren, useEffect, useState } from 'react';
|
||||
|
||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import {
|
||||
ContextStoreTargetedRecordsRule,
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
} from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
@ -18,6 +20,7 @@ export type JestContextStoreSetterMocks = {
|
||||
contextStoreFilters?: RecordFilter[];
|
||||
contextStoreCurrentObjectMetadataNameSingular?: string;
|
||||
contextStoreCurrentViewId?: string;
|
||||
contextStoreCurrentViewType?: ContextStoreViewType;
|
||||
};
|
||||
|
||||
type JestContextStoreSetterProps =
|
||||
@ -31,6 +34,7 @@ export const JestContextStoreSetter = ({
|
||||
contextStoreNumberOfSelectedRecords = 0,
|
||||
contextStoreCurrentObjectMetadataNameSingular = 'company',
|
||||
contextStoreFilters = [],
|
||||
contextStoreCurrentViewType,
|
||||
children,
|
||||
}: JestContextStoreSetterProps) => {
|
||||
const setContextStoreTargetedRecordsRule = useSetRecoilComponentStateV2(
|
||||
@ -54,6 +58,10 @@ export const JestContextStoreSetter = ({
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const setContextStoreCurrentViewType = useSetRecoilComponentStateV2(
|
||||
contextStoreCurrentViewTypeComponentState,
|
||||
);
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular: contextStoreCurrentObjectMetadataNameSingular,
|
||||
});
|
||||
@ -67,7 +75,7 @@ export const JestContextStoreSetter = ({
|
||||
setContextStoreCurrentObjectMetadataItemId(objectMetadataItem.id);
|
||||
setContextStoreNumberOfSelectedRecords(contextStoreNumberOfSelectedRecords);
|
||||
setcontextStoreFiltersComponentState(contextStoreFilters);
|
||||
|
||||
setContextStoreCurrentViewType(contextStoreCurrentViewType ?? null);
|
||||
setIsLoaded(true);
|
||||
}, [
|
||||
setContextStoreTargetedRecordsRule,
|
||||
@ -81,6 +89,8 @@ export const JestContextStoreSetter = ({
|
||||
objectMetadataItem,
|
||||
setContextStoreCurrentViewId,
|
||||
contextStoreCurrentViewId,
|
||||
setContextStoreCurrentViewType,
|
||||
contextStoreCurrentViewType,
|
||||
]);
|
||||
|
||||
return isLoaded ? <>{children}</> : null;
|
||||
|
||||
@ -28,6 +28,7 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
||||
onInitializeRecoilSnapshot,
|
||||
contextStoreTargetedRecordsRule,
|
||||
contextStoreCurrentViewId,
|
||||
contextStoreCurrentViewType,
|
||||
contextStoreNumberOfSelectedRecords,
|
||||
contextStoreCurrentObjectMetadataNameSingular,
|
||||
contextStoreFilters,
|
||||
@ -93,6 +94,7 @@ export const getJestMetadataAndApolloMocksAndActionMenuWrapper = ({
|
||||
contextStoreCurrentObjectMetadataNameSingular={
|
||||
contextStoreCurrentObjectMetadataNameSingular
|
||||
}
|
||||
contextStoreCurrentViewType={contextStoreCurrentViewType}
|
||||
>
|
||||
{children}
|
||||
</JestContextStoreSetter>
|
||||
|
||||
Reference in New Issue
Block a user