321 command menu context chips compact version (#10072)
Closes https://github.com/twentyhq/core-team-issues/issues/321 - Create component - Create stories - Fix bug due to `WorkflowDiagramCanvasEditableEffect`
This commit is contained in:
@ -1,5 +1,4 @@
|
|||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { IconLayoutSidebarRightExpand, getOsControlSymbol } from 'twenty-ui';
|
import { IconLayoutSidebarRightExpand, getOsControlSymbol } from 'twenty-ui';
|
||||||
@ -39,17 +38,11 @@ const StyledSeparator = styled.div<{ size: 'sm' | 'md' }>`
|
|||||||
|
|
||||||
export const RecordIndexActionMenuBarAllActionsButton = () => {
|
export const RecordIndexActionMenuBarAllActionsButton = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { navigateCommandMenu } = useCommandMenu();
|
const { openRootCommandMenu } = useCommandMenu();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledSeparator size="md" />
|
<StyledSeparator size="md" />
|
||||||
<StyledButton
|
<StyledButton onClick={openRootCommandMenu}>
|
||||||
onClick={() =>
|
|
||||||
navigateCommandMenu({
|
|
||||||
page: CommandMenuPages.Root,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<IconLayoutSidebarRightExpand size={theme.icon.size.md} />
|
<IconLayoutSidebarRightExpand size={theme.icon.size.md} />
|
||||||
<StyledButtonLabel>All Actions</StyledButtonLabel>
|
<StyledButtonLabel>All Actions</StyledButtonLabel>
|
||||||
<StyledSeparator size="sm" />
|
<StyledSeparator size="sm" />
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPage
|
|||||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { IconList } from 'twenty-ui';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useOpenActivityRightDrawer = ({
|
export const useOpenActivityRightDrawer = ({
|
||||||
@ -49,6 +50,9 @@ export const useOpenActivityRightDrawer = ({
|
|||||||
|
|
||||||
setViewableRecordId(activityId);
|
setViewableRecordId(activityId);
|
||||||
setViewableRecordNameSingular(objectNameSingular);
|
setViewableRecordNameSingular(objectNameSingular);
|
||||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: objectNameSingular,
|
||||||
|
Icon: IconList,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { isNewViewableRecordLoadingState } from '@/object-record/record-right-dr
|
|||||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||||
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { IconList } from 'twenty-ui';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
|
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
|
||||||
|
|
||||||
@ -75,7 +76,10 @@ export const useOpenCreateActivityDrawer = ({
|
|||||||
customAssignee?: WorkspaceMember;
|
customAssignee?: WorkspaceMember;
|
||||||
}) => {
|
}) => {
|
||||||
setIsNewViewableRecordLoading(true);
|
setIsNewViewableRecordLoading(true);
|
||||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: activityObjectNameSingular,
|
||||||
|
Icon: IconList,
|
||||||
|
});
|
||||||
setViewableRecordId(null);
|
setViewableRecordId(null);
|
||||||
setViewableRecordNameSingular(activityObjectNameSingular);
|
setViewableRecordNameSingular(activityObjectNameSingular);
|
||||||
|
|
||||||
|
|||||||
@ -33,20 +33,23 @@ const StyledChip = styled.button<{
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIconsContainer = styled.div`
|
const StyledIconsContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export type CommandMenuContextChipProps = {
|
||||||
|
Icons: React.ReactNode[];
|
||||||
|
text?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
testId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const CommandMenuContextChip = ({
|
export const CommandMenuContextChip = ({
|
||||||
Icons,
|
Icons,
|
||||||
text,
|
text,
|
||||||
onClick,
|
onClick,
|
||||||
testId,
|
testId,
|
||||||
}: {
|
}: CommandMenuContextChipProps) => {
|
||||||
Icons: React.ReactNode[];
|
|
||||||
text?: string;
|
|
||||||
onClick?: () => void;
|
|
||||||
testId?: string;
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<StyledChip
|
<StyledChip
|
||||||
withText={isNonEmptyString(text)}
|
withText={isNonEmptyString(text)}
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import {
|
||||||
|
CommandMenuContextChip,
|
||||||
|
CommandMenuContextChipProps,
|
||||||
|
} from './CommandMenuContextChip';
|
||||||
|
|
||||||
|
export const CommandMenuContextChipGroups = ({
|
||||||
|
contextChips,
|
||||||
|
}: {
|
||||||
|
contextChips: CommandMenuContextChipProps[];
|
||||||
|
}) => {
|
||||||
|
if (contextChips.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contextChips.length < 3) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{contextChips.map((chip) => (
|
||||||
|
<CommandMenuContextChip
|
||||||
|
key={chip.text}
|
||||||
|
Icons={chip.Icons}
|
||||||
|
text={chip.text}
|
||||||
|
onClick={chip.onClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstChips = contextChips.slice(0, -1);
|
||||||
|
const lastChip = contextChips.at(-1);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{firstChips.length > 0 && (
|
||||||
|
<CommandMenuContextChip
|
||||||
|
Icons={firstChips.map((chip) => chip.Icons?.[0])}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isDefined(lastChip) && (
|
||||||
|
<CommandMenuContextChip
|
||||||
|
Icons={lastChip.Icons}
|
||||||
|
text={lastChip.text}
|
||||||
|
onClick={lastChip.onClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
|
||||||
|
import { CommandMenuContextRecordChipAvatars } from '@/command-menu/components/CommandMenuContextRecordChipAvatars';
|
||||||
|
import { getSelectedRecordsContextText } from '@/command-menu/utils/getRecordContextText';
|
||||||
|
import { useFindManyRecordsSelectedInContextStore } from '@/context-store/hooks/useFindManyRecordsSelectedInContextStore';
|
||||||
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
|
import { CommandMenuContextChipProps } from './CommandMenuContextChip';
|
||||||
|
|
||||||
|
export const CommandMenuContextChipGroupsWithRecordSelection = ({
|
||||||
|
contextChips,
|
||||||
|
objectMetadataItemId,
|
||||||
|
}: {
|
||||||
|
contextChips: CommandMenuContextChipProps[];
|
||||||
|
objectMetadataItemId: string;
|
||||||
|
}) => {
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItemById({
|
||||||
|
objectId: objectMetadataItemId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { records, loading, totalCount } =
|
||||||
|
useFindManyRecordsSelectedInContextStore({
|
||||||
|
limit: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loading || !totalCount) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Avatars = records.map((record) => (
|
||||||
|
<CommandMenuContextRecordChipAvatars
|
||||||
|
objectMetadataItem={objectMetadataItem}
|
||||||
|
key={record.id}
|
||||||
|
record={record}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
const selectedRecordsContextText = getSelectedRecordsContextText(
|
||||||
|
objectMetadataItem,
|
||||||
|
records,
|
||||||
|
totalCount,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CommandMenuContextChipGroups
|
||||||
|
contextChips={[
|
||||||
|
{
|
||||||
|
text: selectedRecordsContextText,
|
||||||
|
Icons: Avatars,
|
||||||
|
},
|
||||||
|
...contextChips,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
|
import { CommandMenuContextChip } from '@/command-menu/components/CommandMenuContextChip';
|
||||||
import { CommandMenuContextRecordChip } from '@/command-menu/components/CommandMenuContextRecordChip';
|
import { CommandMenuContextChipGroups } from '@/command-menu/components/CommandMenuContextChipGroups';
|
||||||
|
import { CommandMenuContextChipGroupsWithRecordSelection } from '@/command-menu/components/CommandMenuContextChipGroupsWithRecordSelection';
|
||||||
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
|
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
|
||||||
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState';
|
||||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
|
|
||||||
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
@ -13,6 +14,7 @@ import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
|||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { useMemo } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import {
|
import {
|
||||||
@ -98,7 +100,9 @@ export const CommandMenuTopBar = () => {
|
|||||||
|
|
||||||
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
const commandMenuPage = useRecoilValue(commandMenuPageState);
|
||||||
|
|
||||||
const { title, Icon } = useRecoilValue(commandMenuPageInfoState);
|
const commandMenuNavigationStack = useRecoilValue(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -106,31 +110,40 @@ export const CommandMenuTopBar = () => {
|
|||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const contextChips = useMemo(() => {
|
||||||
|
return commandMenuNavigationStack
|
||||||
|
.filter((page) => page.page !== CommandMenuPages.Root)
|
||||||
|
.map((page) => {
|
||||||
|
return {
|
||||||
|
Icons: [<page.pageIcon size={theme.icon.size.sm} />],
|
||||||
|
text: page.pageTitle,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, [commandMenuNavigationStack, theme.icon.size.sm]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInputContainer>
|
<StyledInputContainer>
|
||||||
<StyledContentContainer>
|
<StyledContentContainer>
|
||||||
{isCommandMenuV2Enabled && (
|
{isCommandMenuV2Enabled && (
|
||||||
<CommandMenuContextChip
|
<>
|
||||||
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
|
<CommandMenuContextChip
|
||||||
onClick={() => {
|
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
|
||||||
goBackFromCommandMenu();
|
onClick={() => {
|
||||||
}}
|
goBackFromCommandMenu();
|
||||||
testId="command-menu-go-back-button"
|
}}
|
||||||
/>
|
testId="command-menu-go-back-button"
|
||||||
)}
|
|
||||||
{commandMenuPage !== CommandMenuPages.SearchRecords &&
|
|
||||||
isDefined(contextStoreCurrentObjectMetadataId) && (
|
|
||||||
<CommandMenuContextRecordChip
|
|
||||||
objectMetadataItemId={contextStoreCurrentObjectMetadataId}
|
|
||||||
/>
|
/>
|
||||||
)}
|
{isDefined(contextStoreCurrentObjectMetadataId) &&
|
||||||
{isDefined(Icon) && (
|
commandMenuPage !== CommandMenuPages.SearchRecords ? (
|
||||||
<CommandMenuContextChip
|
<CommandMenuContextChipGroupsWithRecordSelection
|
||||||
Icons={[<Icon size={theme.icon.size.sm} />]}
|
contextChips={contextChips}
|
||||||
text={title}
|
objectMetadataItemId={contextStoreCurrentObjectMetadataId}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<CommandMenuContextChipGroups contextChips={contextChips} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(commandMenuPage === CommandMenuPages.Root ||
|
{(commandMenuPage === CommandMenuPages.Root ||
|
||||||
commandMenuPage === CommandMenuPages.SearchRecords) && (
|
commandMenuPage === CommandMenuPages.SearchRecords) && (
|
||||||
<StyledInput
|
<StyledInput
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
|||||||
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
|
||||||
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext';
|
||||||
import { HttpResponse, graphql } from 'msw';
|
import { HttpResponse, graphql } from 'msw';
|
||||||
|
import { IconDotsVertical } from 'twenty-ui';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter';
|
import { JestContextStoreSetter } from '~/testing/jest/JestContextStoreSetter';
|
||||||
@ -89,6 +90,8 @@ const meta: Meta<typeof CommandMenu> = {
|
|||||||
setCommandMenuNavigationStack([
|
setCommandMenuNavigationStack([
|
||||||
{
|
{
|
||||||
page: CommandMenuPages.Root,
|
page: CommandMenuPages.Root,
|
||||||
|
pageTitle: 'Command Menu',
|
||||||
|
pageIcon: IconDotsVertical,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import {
|
||||||
|
ComponentDecorator,
|
||||||
|
IconBuildingSkyscraper,
|
||||||
|
IconSearch,
|
||||||
|
IconSettingsAutomation,
|
||||||
|
IconUser,
|
||||||
|
} from 'twenty-ui';
|
||||||
|
import { CommandMenuContextChipGroups } from '../CommandMenuContextChipGroups';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const meta: Meta<typeof CommandMenuContextChipGroups> = {
|
||||||
|
title: 'Modules/CommandMenu/CommandMenuContextChipGroups',
|
||||||
|
component: CommandMenuContextChipGroups,
|
||||||
|
decorators: [
|
||||||
|
(Story) => <StyledContainer>{Story()}</StyledContainer>,
|
||||||
|
ComponentDecorator,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof CommandMenuContextChipGroups>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
contextChips: [
|
||||||
|
{
|
||||||
|
Icons: [<IconBuildingSkyscraper size={16} />],
|
||||||
|
text: 'Company',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconUser size={16} />],
|
||||||
|
text: 'Person',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SingleChip: Story = {
|
||||||
|
args: {
|
||||||
|
contextChips: [
|
||||||
|
{
|
||||||
|
Icons: [<IconUser size={16} />],
|
||||||
|
text: 'Person',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ThreeChipsWithIcons: Story = {
|
||||||
|
args: {
|
||||||
|
contextChips: [
|
||||||
|
{
|
||||||
|
Icons: [<IconBuildingSkyscraper size={16} />],
|
||||||
|
text: 'Company',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconUser size={16} />],
|
||||||
|
text: 'Person',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconSettingsAutomation size={16} />],
|
||||||
|
text: 'Settings',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FourChipsWithIcons: Story = {
|
||||||
|
args: {
|
||||||
|
contextChips: [
|
||||||
|
{
|
||||||
|
Icons: [<IconBuildingSkyscraper size={16} />],
|
||||||
|
text: 'Company',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconUser size={16} />],
|
||||||
|
text: 'Person',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconSettingsAutomation size={16} />],
|
||||||
|
text: 'Settings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icons: [<IconSearch size={16} />],
|
||||||
|
text: 'Search',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -9,7 +9,7 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState
|
|||||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
|
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageTitle';
|
||||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
||||||
import { IconSearch } from 'twenty-ui';
|
import { IconList, IconSearch } from 'twenty-ui';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
@ -53,9 +53,7 @@ describe('useCommandMenu', () => {
|
|||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.commandMenu.navigateCommandMenu({
|
result.current.commandMenu.openRootCommandMenu();
|
||||||
page: CommandMenuPages.Root,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.isCommandMenuOpened).toBe(true);
|
expect(result.current.isCommandMenuOpened).toBe(true);
|
||||||
@ -119,7 +117,8 @@ describe('useCommandMenu', () => {
|
|||||||
act(() => {
|
act(() => {
|
||||||
result.current.commandMenu.navigateCommandMenu({
|
result.current.commandMenu.navigateCommandMenu({
|
||||||
page: CommandMenuPages.ViewRecord,
|
page: CommandMenuPages.ViewRecord,
|
||||||
pageTitle: 'View Record',
|
pageTitle: 'Company',
|
||||||
|
pageIcon: IconList,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -131,13 +130,14 @@ describe('useCommandMenu', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: CommandMenuPages.ViewRecord,
|
page: CommandMenuPages.ViewRecord,
|
||||||
pageTitle: 'View Record',
|
pageTitle: 'Company',
|
||||||
|
pageIcon: IconList,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord);
|
expect(result.current.commandMenuPage).toBe(CommandMenuPages.ViewRecord);
|
||||||
expect(result.current.commandMenuPageInfo).toEqual({
|
expect(result.current.commandMenuPageInfo).toEqual({
|
||||||
title: 'View Record',
|
title: 'Company',
|
||||||
Icon: undefined,
|
Icon: IconList,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -155,7 +155,8 @@ describe('useCommandMenu', () => {
|
|||||||
act(() => {
|
act(() => {
|
||||||
result.current.commandMenu.navigateCommandMenu({
|
result.current.commandMenu.navigateCommandMenu({
|
||||||
page: CommandMenuPages.ViewRecord,
|
page: CommandMenuPages.ViewRecord,
|
||||||
pageTitle: 'View Record',
|
pageTitle: 'Company',
|
||||||
|
pageIcon: IconList,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -167,7 +168,8 @@ describe('useCommandMenu', () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
page: CommandMenuPages.ViewRecord,
|
page: CommandMenuPages.ViewRecord,
|
||||||
pageTitle: 'View Record',
|
pageTitle: 'Company',
|
||||||
|
pageIcon: IconList,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -23,8 +23,9 @@ import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType
|
|||||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||||
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
import { viewableRecordNameSingularState } from '@/object-record/record-right-drawer/states/viewableRecordNameSingularState';
|
||||||
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
|
import { emitRightDrawerCloseEvent } from '@/ui/layout/right-drawer/utils/emitRightDrawerCloseEvent';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { IconSearch } from 'twenty-ui';
|
import { IconDotsVertical, IconList, IconSearch } from 'twenty-ui';
|
||||||
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
|
||||||
|
|
||||||
export const useCommandMenu = () => {
|
export const useCommandMenu = () => {
|
||||||
@ -123,6 +124,14 @@ export const useCommandMenu = () => {
|
|||||||
[openCommandMenu],
|
[openCommandMenu],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openRootCommandMenu = useCallback(() => {
|
||||||
|
navigateCommandMenu({
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
pageTitle: 'Command Menu',
|
||||||
|
pageIcon: IconDotsVertical,
|
||||||
|
});
|
||||||
|
}, [navigateCommandMenu]);
|
||||||
|
|
||||||
const toggleCommandMenu = useRecoilCallback(
|
const toggleCommandMenu = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async () => {
|
async () => {
|
||||||
@ -135,12 +144,10 @@ export const useCommandMenu = () => {
|
|||||||
if (isCommandMenuOpened) {
|
if (isCommandMenuOpened) {
|
||||||
closeCommandMenu();
|
closeCommandMenu();
|
||||||
} else {
|
} else {
|
||||||
navigateCommandMenu({
|
openRootCommandMenu();
|
||||||
page: CommandMenuPages.Root,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[closeCommandMenu, navigateCommandMenu],
|
[closeCommandMenu, openRootCommandMenu],
|
||||||
);
|
);
|
||||||
|
|
||||||
const goBackFromCommandMenu = useRecoilCallback(
|
const goBackFromCommandMenu = useRecoilCallback(
|
||||||
@ -204,6 +211,8 @@ export const useCommandMenu = () => {
|
|||||||
set(viewableRecordIdState, recordId);
|
set(viewableRecordIdState, recordId);
|
||||||
navigateCommandMenu({
|
navigateCommandMenu({
|
||||||
page: CommandMenuPages.ViewRecord,
|
page: CommandMenuPages.ViewRecord,
|
||||||
|
pageTitle: objectNameSingular,
|
||||||
|
pageIcon: IconList,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -267,6 +276,7 @@ export const useCommandMenu = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
openRootCommandMenu,
|
||||||
closeCommandMenu,
|
closeCommandMenu,
|
||||||
navigateCommandMenu,
|
navigateCommandMenu,
|
||||||
navigateCommandMenuHistory,
|
navigateCommandMenuHistory,
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { IconComponent, createState } from 'twenty-ui';
|
|||||||
|
|
||||||
export type CommandMenuNavigationStackItem = {
|
export type CommandMenuNavigationStackItem = {
|
||||||
page: CommandMenuPages;
|
page: CommandMenuPages;
|
||||||
pageTitle?: string;
|
pageTitle: string;
|
||||||
pageIcon?: IconComponent;
|
pageIcon: IconComponent;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const commandMenuNavigationStackState = createState<
|
export const commandMenuNavigationStackState = createState<
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
|||||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { IconList } from 'twenty-ui';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export const RecordBoardColumnNewOpportunity = ({
|
export const RecordBoardColumnNewOpportunity = ({
|
||||||
@ -52,7 +53,10 @@ export const RecordBoardColumnNewOpportunity = ({
|
|||||||
|
|
||||||
setViewableRecordId(newRecordId);
|
setViewableRecordId(newRecordId);
|
||||||
setViewableRecordNameSingular(CoreObjectNameSingular.Company);
|
setViewableRecordNameSingular(CoreObjectNameSingular.Company);
|
||||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: 'Company',
|
||||||
|
Icon: IconList,
|
||||||
|
});
|
||||||
|
|
||||||
if (isDefined(createdCompany)) {
|
if (isDefined(createdCompany)) {
|
||||||
handleEntitySelect(position, createdCompany);
|
handleEntitySelect(position, createdCompany);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd
|
|||||||
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
|
||||||
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { IconList } from 'twenty-ui';
|
||||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||||
|
|
||||||
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
export const DEFAULT_CELL_SCOPE: HotkeyScope = {
|
||||||
@ -123,7 +124,10 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => {
|
|||||||
leaveTableFocus();
|
leaveTableFocus();
|
||||||
setViewableRecordId(recordId);
|
setViewableRecordId(recordId);
|
||||||
setViewableRecordNameSingular(objectNameSingular);
|
setViewableRecordNameSingular(objectNameSingular);
|
||||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: objectNameSingular,
|
||||||
|
Icon: IconList,
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import { viewableRecordNameSingularState } from '@/object-record/record-right-dr
|
|||||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
import { IconEye } from 'twenty-ui';
|
||||||
import {
|
import {
|
||||||
FieldMetadataType,
|
FieldMetadataType,
|
||||||
RelationDefinitionType,
|
RelationDefinitionType,
|
||||||
@ -109,7 +110,10 @@ export const useAddNewRecordAndOpenRightDrawer = ({
|
|||||||
|
|
||||||
setViewableRecordId(newRecordId);
|
setViewableRecordId(newRecordId);
|
||||||
setViewableRecordNameSingular(relationObjectMetadataNameSingular);
|
setViewableRecordNameSingular(relationObjectMetadataNameSingular);
|
||||||
openRightDrawer(RightDrawerPages.ViewRecord);
|
openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: 'View Record',
|
||||||
|
Icon: IconEye,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,12 +7,11 @@ import {
|
|||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
import { CommandMenuPages } from '@/command-menu/types/CommandMenuPages';
|
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { FeatureFlagKey } from '~/generated/graphql';
|
import { FeatureFlagKey } from '~/generated/graphql';
|
||||||
|
|
||||||
export const PageHeaderOpenCommandMenuButton = () => {
|
export const PageHeaderOpenCommandMenuButton = () => {
|
||||||
const { navigateCommandMenu } = useCommandMenu();
|
const { openRootCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
@ -31,11 +30,7 @@ export const PageHeaderOpenCommandMenuButton = () => {
|
|||||||
accent="default"
|
accent="default"
|
||||||
hotkeys={[getOsControlSymbol(), 'K']}
|
hotkeys={[getOsControlSymbol(), 'K']}
|
||||||
ariaLabel="Open command menu"
|
ariaLabel="Open command menu"
|
||||||
onClick={() => {
|
onClick={openRootCommandMenu}
|
||||||
navigateCommandMenu({
|
|
||||||
page: CommandMenuPages.Root,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -44,11 +39,7 @@ export const PageHeaderOpenCommandMenuButton = () => {
|
|||||||
dataTestId="more-showpage-button"
|
dataTestId="more-showpage-button"
|
||||||
accent="default"
|
accent="default"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => {
|
onClick={openRootCommandMenu}
|
||||||
navigateCommandMenu({
|
|
||||||
page: CommandMenuPages.Root,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
|||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { RecoilRoot, useRecoilValue } from 'recoil';
|
import { RecoilRoot, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { IconList } from 'twenty-ui';
|
||||||
import { isRightDrawerOpenState } from '../../states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '../../states/isRightDrawerOpenState';
|
||||||
import { rightDrawerPageState } from '../../states/rightDrawerPageState';
|
import { rightDrawerPageState } from '../../states/rightDrawerPageState';
|
||||||
import { RightDrawerPages } from '../../types/RightDrawerPages';
|
import { RightDrawerPages } from '../../types/RightDrawerPages';
|
||||||
@ -33,7 +34,10 @@ describe('useRightDrawer', () => {
|
|||||||
expect(result.current.closeRightDrawer).toBeInstanceOf(Function);
|
expect(result.current.closeRightDrawer).toBeInstanceOf(Function);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
result.current.openRightDrawer(RightDrawerPages.ViewRecord);
|
result.current.openRightDrawer(RightDrawerPages.ViewRecord, {
|
||||||
|
title: 'Company',
|
||||||
|
Icon: IconList,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.rightDrawerPage).toEqual(RightDrawerPages.ViewRecord);
|
expect(result.current.rightDrawerPage).toEqual(RightDrawerPages.ViewRecord);
|
||||||
|
|||||||
@ -30,9 +30,9 @@ export const useRightDrawer = () => {
|
|||||||
({ set }) =>
|
({ set }) =>
|
||||||
(
|
(
|
||||||
rightDrawerPage: RightDrawerPages,
|
rightDrawerPage: RightDrawerPages,
|
||||||
commandMenuPageInfo?: {
|
commandMenuPageInfo: {
|
||||||
title?: string;
|
title: string;
|
||||||
Icon?: IconComponent;
|
Icon: IconComponent;
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
if (isCommandMenuV2Enabled) {
|
if (isCommandMenuV2Enabled) {
|
||||||
@ -41,8 +41,8 @@ export const useRightDrawer = () => {
|
|||||||
|
|
||||||
navigateCommandMenu({
|
navigateCommandMenu({
|
||||||
page: commandMenuPage,
|
page: commandMenuPage,
|
||||||
pageTitle: commandMenuPageInfo?.title,
|
pageTitle: commandMenuPageInfo.title,
|
||||||
pageIcon: commandMenuPageInfo?.Icon,
|
pageIcon: commandMenuPageInfo.Icon,
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
|
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
|
||||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
@ -32,11 +33,17 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
|
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||||
|
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
const handleSelectionChange = useCallback(
|
const handleSelectionChange = useCallback(
|
||||||
({ nodes }: OnSelectionChangeParams) => {
|
({ nodes }: OnSelectionChangeParams) => {
|
||||||
const selectedNode = nodes[0] as WorkflowDiagramNode;
|
const selectedNode = nodes[0] as WorkflowDiagramNode;
|
||||||
const isClosingStep = isDefined(selectedNode) === false;
|
const isClosingStep = isDefined(selectedNode) === false;
|
||||||
|
|
||||||
|
setCommandMenuNavigationStack([]);
|
||||||
|
|
||||||
if (isClosingStep) {
|
if (isClosingStep) {
|
||||||
closeRightDrawer();
|
closeRightDrawer();
|
||||||
closeCommandMenu();
|
closeCommandMenu();
|
||||||
@ -69,14 +76,15 @@ export const WorkflowDiagramCanvasEditableEffect = () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
setCommandMenuNavigationStack,
|
||||||
setWorkflowSelectedNode,
|
setWorkflowSelectedNode,
|
||||||
setHotkeyScope,
|
setHotkeyScope,
|
||||||
openRightDrawer,
|
openRightDrawer,
|
||||||
|
getIcon,
|
||||||
closeRightDrawer,
|
closeRightDrawer,
|
||||||
closeCommandMenu,
|
closeCommandMenu,
|
||||||
startNodeCreation,
|
|
||||||
getIcon,
|
|
||||||
t,
|
t,
|
||||||
|
startNodeCreation,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const useStartNodeCreation = () => {
|
|||||||
Icon: IconSettingsAutomation,
|
Icon: IconSettingsAutomation,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[openRightDrawer, setWorkflowCreateStepFromParentStepId, setHotkeyScope],
|
[setWorkflowCreateStepFromParentStepId, setHotkeyScope, openRightDrawer],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
|
|||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { useCreateStep } from '../useCreateStep';
|
import { useCreateStep } from '../useCreateStep';
|
||||||
|
|
||||||
const mockOpenRightDrawer = jest.fn();
|
|
||||||
const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
|
const mockCreateDraftFromWorkflowVersion = jest.fn().mockResolvedValue('457');
|
||||||
const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
|
const mockCreateWorkflowVersionStep = jest.fn().mockResolvedValue({
|
||||||
data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
|
data: { createWorkflowVersionStep: { id: '1', type: 'CODE' } },
|
||||||
@ -14,12 +13,6 @@ jest.mock('recoil', () => ({
|
|||||||
atom: (params: any) => params,
|
atom: (params: any) => params,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('@/ui/layout/right-drawer/hooks/useRightDrawer', () => ({
|
|
||||||
useRightDrawer: () => ({
|
|
||||||
openRightDrawer: mockOpenRightDrawer,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock(
|
jest.mock(
|
||||||
'@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep',
|
'@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep',
|
||||||
() => ({
|
() => ({
|
||||||
@ -56,6 +49,5 @@ describe('useCreateStep', () => {
|
|||||||
await result.current.createStep('CODE');
|
await result.current.createStep('CODE');
|
||||||
|
|
||||||
expect(mockCreateWorkflowVersionStep).toHaveBeenCalled();
|
expect(mockCreateWorkflowVersionStep).toHaveBeenCalled();
|
||||||
expect(mockOpenRightDrawer).toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
|
||||||
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
|
||||||
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
|
import { useGetUpdatableWorkflowVersion } from '@/workflow/hooks/useGetUpdatableWorkflowVersion';
|
||||||
import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
|
import { workflowLastCreatedStepIdState } from '@/workflow/states/workflowLastCreatedStepIdState';
|
||||||
import {
|
import {
|
||||||
@ -7,19 +5,16 @@ import {
|
|||||||
WorkflowWithCurrentVersion,
|
WorkflowWithCurrentVersion,
|
||||||
} from '@/workflow/types/Workflow';
|
} from '@/workflow/types/Workflow';
|
||||||
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
import { workflowSelectedNodeState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeState';
|
||||||
import { getWorkflowNodeIconKey } from '@/workflow/workflow-diagram/utils/getWorkflowNodeIconKey';
|
|
||||||
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
|
import { useCreateWorkflowVersionStep } from '@/workflow/workflow-steps/hooks/useCreateWorkflowVersionStep';
|
||||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
|
import { workflowCreateStepFromParentStepIdState } from '@/workflow/workflow-steps/states/workflowCreateStepFromParentStepIdState';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { useIcons } from 'twenty-ui';
|
|
||||||
|
|
||||||
export const useCreateStep = ({
|
export const useCreateStep = ({
|
||||||
workflow,
|
workflow,
|
||||||
}: {
|
}: {
|
||||||
workflow: WorkflowWithCurrentVersion;
|
workflow: WorkflowWithCurrentVersion;
|
||||||
}) => {
|
}) => {
|
||||||
const { getIcon } = useIcons();
|
|
||||||
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
|
const { createWorkflowVersionStep } = useCreateWorkflowVersionStep();
|
||||||
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
const setWorkflowSelectedNode = useSetRecoilState(workflowSelectedNodeState);
|
||||||
const setWorkflowLastCreatedStepId = useSetRecoilState(
|
const setWorkflowLastCreatedStepId = useSetRecoilState(
|
||||||
@ -32,8 +27,6 @@ export const useCreateStep = ({
|
|||||||
|
|
||||||
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
const { getUpdatableWorkflowVersion } = useGetUpdatableWorkflowVersion();
|
||||||
|
|
||||||
const { openRightDrawer } = useRightDrawer();
|
|
||||||
|
|
||||||
const createStep = async (newStepType: WorkflowStepType) => {
|
const createStep = async (newStepType: WorkflowStepType) => {
|
||||||
if (!isDefined(workflowCreateStepFromParentStepId)) {
|
if (!isDefined(workflowCreateStepFromParentStepId)) {
|
||||||
throw new Error('Select a step to create a new step from first.');
|
throw new Error('Select a step to create a new step from first.');
|
||||||
@ -54,18 +47,6 @@ export const useCreateStep = ({
|
|||||||
|
|
||||||
setWorkflowSelectedNode(createdStep.id);
|
setWorkflowSelectedNode(createdStep.id);
|
||||||
setWorkflowLastCreatedStepId(createdStep.id);
|
setWorkflowLastCreatedStepId(createdStep.id);
|
||||||
|
|
||||||
const stepIcon = getWorkflowNodeIconKey({
|
|
||||||
nodeType: 'action',
|
|
||||||
actionType: createdStep.type as WorkflowStepType,
|
|
||||||
name: createdStep.name,
|
|
||||||
isLeafNode: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
openRightDrawer(RightDrawerPages.WorkflowStepEdit, {
|
|
||||||
title: createdStep.name,
|
|
||||||
Icon: getIcon(stepIcon),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user