320 new command menu navigation bar buttons (#10018)
Closes https://github.com/twentyhq/core-team-issues/issues/320 https://github.com/user-attachments/assets/8082e986-07fd-46fb-9652-ad006aa9dac8
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
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';
|
||||||
@ -38,11 +39,17 @@ const StyledSeparator = styled.div<{ size: 'sm' | 'md' }>`
|
|||||||
|
|
||||||
export const RecordIndexActionMenuBarAllActionsButton = () => {
|
export const RecordIndexActionMenuBarAllActionsButton = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { openCommandMenu } = useCommandMenu();
|
const { navigateCommandMenu } = useCommandMenu();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledSeparator size="md" />
|
<StyledSeparator size="md" />
|
||||||
<StyledButton onClick={() => openCommandMenu()}>
|
<StyledButton
|
||||||
|
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" />
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
||||||
|
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey';
|
||||||
import { RecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter';
|
import { RecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter';
|
||||||
import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter';
|
import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter';
|
||||||
import { RecordAgnosticActionsKey } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKey';
|
import { RecordAgnosticActionsKey } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKey';
|
||||||
@ -91,7 +92,10 @@ export const CommandMenuContainer = ({
|
|||||||
value={{
|
value={{
|
||||||
isInRightDrawer: false,
|
isInRightDrawer: false,
|
||||||
onActionExecutedCallback: ({ key }) => {
|
onActionExecutedCallback: ({ key }) => {
|
||||||
if (key !== RecordAgnosticActionsKey.SEARCH_RECORDS) {
|
if (
|
||||||
|
key !== RecordAgnosticActionsKey.SEARCH_RECORDS &&
|
||||||
|
key !== NoSelectionRecordActionKeys.CREATE_NEW_RECORD
|
||||||
|
) {
|
||||||
toggleCommandMenu();
|
toggleCommandMenu();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { Fragment } from 'react/jsx-runtime';
|
import { Fragment } from 'react/jsx-runtime';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
const StyledChip = styled.div`
|
const StyledChip = styled.button<{
|
||||||
|
withText: boolean;
|
||||||
|
onClick?: () => void;
|
||||||
|
}>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: ${({ theme }) => theme.background.transparent.light};
|
background: ${({ theme }) => theme.background.transparent.light};
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
@ -10,11 +15,21 @@ const StyledChip = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
height: ${({ theme }) => theme.spacing(6)};
|
height: ${({ theme }) => theme.spacing(6)};
|
||||||
padding: 0 ${({ theme }) => theme.spacing(2)};
|
/* If the chip has text, we add extra padding to have a more balanced design */
|
||||||
|
padding: 0
|
||||||
|
${({ theme, withText }) => (withText ? theme.spacing(2) : theme.spacing(1))};
|
||||||
font-size: ${({ theme }) => theme.font.size.sm};
|
font-size: ${({ theme }) => theme.font.size.sm};
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
cursor: ${({ onClick }) => (isDefined(onClick) ? 'pointer' : 'default')};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${({ onClick, theme }) =>
|
||||||
|
isDefined(onClick)
|
||||||
|
? theme.background.transparent.medium
|
||||||
|
: theme.background.transparent.light};
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIconsContainer = styled.div`
|
const StyledIconsContainer = styled.div`
|
||||||
@ -24,18 +39,26 @@ const StyledIconsContainer = styled.div`
|
|||||||
export const CommandMenuContextChip = ({
|
export const CommandMenuContextChip = ({
|
||||||
Icons,
|
Icons,
|
||||||
text,
|
text,
|
||||||
|
onClick,
|
||||||
|
testId,
|
||||||
}: {
|
}: {
|
||||||
Icons: React.ReactNode[];
|
Icons: React.ReactNode[];
|
||||||
text?: string;
|
text?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
testId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<StyledChip>
|
<StyledChip
|
||||||
|
withText={isNonEmptyString(text)}
|
||||||
|
onClick={onClick}
|
||||||
|
data-testid={testId}
|
||||||
|
>
|
||||||
<StyledIconsContainer>
|
<StyledIconsContainer>
|
||||||
{Icons.map((Icon, index) => (
|
{Icons.map((Icon, index) => (
|
||||||
<Fragment key={index}>{Icon}</Fragment>
|
<Fragment key={index}>{Icon}</Fragment>
|
||||||
))}
|
))}
|
||||||
</StyledIconsContainer>
|
</StyledIconsContainer>
|
||||||
<span>{text}</span>
|
{text && <span>{text}</span>}
|
||||||
</StyledChip>
|
</StyledChip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,12 +9,21 @@ import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchS
|
|||||||
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';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
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 { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
import { IconX, LightIconButton, useIsMobile } from 'twenty-ui';
|
import {
|
||||||
|
Button,
|
||||||
|
IconChevronLeft,
|
||||||
|
IconX,
|
||||||
|
LightIconButton,
|
||||||
|
getOsControlSymbol,
|
||||||
|
useIsMobile,
|
||||||
|
} from 'twenty-ui';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
const StyledInputContainer = styled.div`
|
const StyledInputContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -81,7 +90,7 @@ export const CommandMenuTopBar = () => {
|
|||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const { closeCommandMenu } = useCommandMenu();
|
const { closeCommandMenu, goBackFromCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||||
contextStoreCurrentObjectMetadataIdComponentState,
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
@ -93,9 +102,22 @@ export const CommandMenuTopBar = () => {
|
|||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInputContainer>
|
<StyledInputContainer>
|
||||||
<StyledContentContainer>
|
<StyledContentContainer>
|
||||||
|
{isCommandMenuV2Enabled && (
|
||||||
|
<CommandMenuContextChip
|
||||||
|
Icons={[<IconChevronLeft size={theme.icon.size.sm} />]}
|
||||||
|
onClick={() => {
|
||||||
|
goBackFromCommandMenu();
|
||||||
|
}}
|
||||||
|
testId="command-menu-go-back-button"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{commandMenuPage !== CommandMenuPages.SearchRecords &&
|
{commandMenuPage !== CommandMenuPages.SearchRecords &&
|
||||||
isDefined(contextStoreCurrentObjectMetadataId) && (
|
isDefined(contextStoreCurrentObjectMetadataId) && (
|
||||||
<CommandMenuContextRecordChip
|
<CommandMenuContextRecordChip
|
||||||
@ -120,14 +142,29 @@ export const CommandMenuTopBar = () => {
|
|||||||
)}
|
)}
|
||||||
</StyledContentContainer>
|
</StyledContentContainer>
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<StyledCloseButtonContainer>
|
<>
|
||||||
<LightIconButton
|
{isCommandMenuV2Enabled ? (
|
||||||
accent={'tertiary'}
|
<Button
|
||||||
size={'medium'}
|
Icon={IconX}
|
||||||
Icon={IconX}
|
dataTestId="page-header-close-command-menu-button"
|
||||||
onClick={closeCommandMenu}
|
size={'small'}
|
||||||
/>
|
variant="secondary"
|
||||||
</StyledCloseButtonContainer>
|
accent="default"
|
||||||
|
hotkeys={[getOsControlSymbol(), 'K']}
|
||||||
|
ariaLabel="Close command menu"
|
||||||
|
onClick={closeCommandMenu}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<StyledCloseButtonContainer>
|
||||||
|
<LightIconButton
|
||||||
|
accent={'tertiary'}
|
||||||
|
size={'medium'}
|
||||||
|
Icon={IconX}
|
||||||
|
onClick={closeCommandMenu}
|
||||||
|
/>
|
||||||
|
</StyledCloseButtonContainer>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</StyledInputContainer>
|
</StyledInputContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,10 +16,13 @@ import { sleep } from '~/utils/sleep';
|
|||||||
|
|
||||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter';
|
import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter';
|
||||||
|
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||||
|
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 { 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';
|
||||||
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
import { getCompaniesMock } from '~/testing/mock-data/companies';
|
||||||
@ -29,6 +32,20 @@ const openTimeout = 50;
|
|||||||
|
|
||||||
const companiesMock = getCompaniesMock();
|
const companiesMock = getCompaniesMock();
|
||||||
|
|
||||||
|
// Mock workspace with feature flag enabled
|
||||||
|
const mockWorkspaceWithFeatureFlag = {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [
|
||||||
|
...(mockCurrentWorkspace.featureFlags || []),
|
||||||
|
{
|
||||||
|
id: 'mock-id',
|
||||||
|
key: FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
|
value: true,
|
||||||
|
workspaceId: mockCurrentWorkspace.id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
const ContextStoreDecorator: Decorator = (Story) => {
|
const ContextStoreDecorator: Decorator = (Story) => {
|
||||||
return (
|
return (
|
||||||
<RecordFiltersComponentInstanceContext.Provider
|
<RecordFiltersComponentInstanceContext.Provider
|
||||||
@ -62,10 +79,18 @@ const meta: Meta<typeof CommandMenu> = {
|
|||||||
const setIsCommandMenuOpened = useSetRecoilState(
|
const setIsCommandMenuOpened = useSetRecoilState(
|
||||||
isCommandMenuOpenedState,
|
isCommandMenuOpenedState,
|
||||||
);
|
);
|
||||||
|
const setCommandMenuNavigationStack = useSetRecoilState(
|
||||||
|
commandMenuNavigationStackState,
|
||||||
|
);
|
||||||
|
|
||||||
setCurrentWorkspace(mockCurrentWorkspace);
|
setCurrentWorkspace(mockWorkspaceWithFeatureFlag);
|
||||||
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
setCurrentWorkspaceMember(mockedWorkspaceMemberData);
|
||||||
setIsCommandMenuOpened(true);
|
setIsCommandMenuOpened(true);
|
||||||
|
setCommandMenuNavigationStack([
|
||||||
|
{
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
return <Story />;
|
return <Story />;
|
||||||
},
|
},
|
||||||
@ -168,3 +193,28 @@ export const NoResultsSearchFallback: Story = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const GoBack: Story = {
|
||||||
|
play: async () => {
|
||||||
|
const canvas = within(document.body);
|
||||||
|
const goBackButton = await canvas.findByTestId(
|
||||||
|
'command-menu-go-back-button',
|
||||||
|
);
|
||||||
|
await userEvent.click(goBackButton);
|
||||||
|
await expect(goBackButton).not.toBeVisible();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ClickOnSearchRecordsAndGoBack: Story = {
|
||||||
|
play: async () => {
|
||||||
|
const canvas = within(document.body);
|
||||||
|
const searchRecordsButton = await canvas.findByText('Search records');
|
||||||
|
await userEvent.click(searchRecordsButton);
|
||||||
|
await sleep(openTimeout);
|
||||||
|
const goBackButton = await canvas.findByTestId(
|
||||||
|
'command-menu-go-back-button',
|
||||||
|
);
|
||||||
|
await userEvent.click(goBackButton);
|
||||||
|
expect(await canvas.findByText('Search records')).toBeVisible();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -53,7 +53,9 @@ describe('useCommandMenu', () => {
|
|||||||
const { result } = renderHooks();
|
const { result } = renderHooks();
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.commandMenu.openCommandMenu();
|
result.current.commandMenu.navigateCommandMenu({
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.isCommandMenuOpened).toBe(true);
|
expect(result.current.isCommandMenuOpened).toBe(true);
|
||||||
|
|||||||
@ -42,8 +42,16 @@ export const useCommandMenu = () => {
|
|||||||
const { resetContextStoreStates } = useResetContextStoreStates();
|
const { resetContextStoreStates } = useResetContextStoreStates();
|
||||||
|
|
||||||
const openCommandMenu = useRecoilCallback(
|
const openCommandMenu = useRecoilCallback(
|
||||||
({ set }) =>
|
({ snapshot, set }) =>
|
||||||
() => {
|
() => {
|
||||||
|
const isCommandMenuOpened = snapshot
|
||||||
|
.getLoadable(isCommandMenuOpenedState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (isCommandMenuOpened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
copyContextStoreStates({
|
copyContextStoreStates({
|
||||||
instanceIdToCopyFrom: mainContextStoreComponentInstanceId,
|
instanceIdToCopyFrom: mainContextStoreComponentInstanceId,
|
||||||
instanceIdToCopyTo: 'command-menu',
|
instanceIdToCopyTo: 'command-menu',
|
||||||
@ -88,24 +96,6 @@ export const useCommandMenu = () => {
|
|||||||
[goBackToPreviousHotkeyScope, resetContextStoreStates, resetSelectedItem],
|
[goBackToPreviousHotkeyScope, resetContextStoreStates, resetSelectedItem],
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleCommandMenu = useRecoilCallback(
|
|
||||||
({ snapshot, set }) =>
|
|
||||||
async () => {
|
|
||||||
const isCommandMenuOpened = snapshot
|
|
||||||
.getLoadable(isCommandMenuOpenedState)
|
|
||||||
.getValue();
|
|
||||||
|
|
||||||
set(commandMenuSearchState, '');
|
|
||||||
|
|
||||||
if (isCommandMenuOpened) {
|
|
||||||
closeCommandMenu();
|
|
||||||
} else {
|
|
||||||
openCommandMenu();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[closeCommandMenu, openCommandMenu],
|
|
||||||
);
|
|
||||||
|
|
||||||
const navigateCommandMenu = useRecoilCallback(
|
const navigateCommandMenu = useRecoilCallback(
|
||||||
({ snapshot, set }) => {
|
({ snapshot, set }) => {
|
||||||
return ({
|
return ({
|
||||||
@ -133,6 +123,26 @@ export const useCommandMenu = () => {
|
|||||||
[openCommandMenu],
|
[openCommandMenu],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const toggleCommandMenu = useRecoilCallback(
|
||||||
|
({ snapshot, set }) =>
|
||||||
|
async () => {
|
||||||
|
const isCommandMenuOpened = snapshot
|
||||||
|
.getLoadable(isCommandMenuOpenedState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
set(commandMenuSearchState, '');
|
||||||
|
|
||||||
|
if (isCommandMenuOpened) {
|
||||||
|
closeCommandMenu();
|
||||||
|
} else {
|
||||||
|
navigateCommandMenu({
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[closeCommandMenu, navigateCommandMenu],
|
||||||
|
);
|
||||||
|
|
||||||
const goBackFromCommandMenu = useRecoilCallback(
|
const goBackFromCommandMenu = useRecoilCallback(
|
||||||
({ snapshot, set }) => {
|
({ snapshot, set }) => {
|
||||||
return () => {
|
return () => {
|
||||||
@ -257,7 +267,6 @@ export const useCommandMenu = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
openCommandMenu,
|
|
||||||
closeCommandMenu,
|
closeCommandMenu,
|
||||||
navigateCommandMenu,
|
navigateCommandMenu,
|
||||||
navigateCommandMenuHistory,
|
navigateCommandMenuHistory,
|
||||||
|
|||||||
@ -7,11 +7,12 @@ 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 { openCommandMenu } = useCommandMenu();
|
const { navigateCommandMenu } = useCommandMenu();
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
@ -30,7 +31,11 @@ export const PageHeaderOpenCommandMenuButton = () => {
|
|||||||
accent="default"
|
accent="default"
|
||||||
hotkeys={[getOsControlSymbol(), 'K']}
|
hotkeys={[getOsControlSymbol(), 'K']}
|
||||||
ariaLabel="Open command menu"
|
ariaLabel="Open command menu"
|
||||||
onClick={openCommandMenu}
|
onClick={() => {
|
||||||
|
navigateCommandMenu({
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<IconButton
|
<IconButton
|
||||||
@ -39,7 +44,11 @@ export const PageHeaderOpenCommandMenuButton = () => {
|
|||||||
dataTestId="more-showpage-button"
|
dataTestId="more-showpage-button"
|
||||||
accent="default"
|
accent="default"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={openCommandMenu}
|
onClick={() => {
|
||||||
|
navigateCommandMenu({
|
||||||
|
page: CommandMenuPages.Root,
|
||||||
|
});
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user