Hide the command menu button while the mobile side panel is open (#23471)
On mobile the side panel covers the page, but the page header stays mounted underneath. Its command menu button (`⌘K`, the `⋮` icon) sits at the same coordinates as the panel's own close button, so the two icons render on top of each other. Measured on a 390x844 viewport with the AI chat open: - `Command Menu` button at `x=346, y=8, 32x32` - `Close side panel` button at `x=358, y=14, 24x24` `SidePanelToggleButton` already hid itself for the command menu and search pages, but the AI chat pages (`AskAI`, `ViewPreviousAiChats`) are not in `COMMAND_MENU_SIDE_PANEL_PAGES`, so the button stayed and overlapped. ## Change Hide the button on mobile whenever the side panel is open, rather than enumerating pages — the header is not reachable behind a full-screen panel either way. Layout customization mode is the exception and keeps it: `alignWithSidePanelTopBar` deliberately repositions the button into the side panel top bar there, so that path is preserved. Desktop is unaffected. ## Testing Three cases added to `SidePanelToggleButton.test.tsx` (hidden on mobile with the panel open, kept on mobile in layout customization mode, kept on desktop with the AI chat open); the `useIsMobile` mock is now switchable per test. All 10 tests pass. Verified in the browser at 390x844: with the AI chat open only `Close side panel` remains in the top bar, and the button reappears once the panel is closed. --- _Generated by [Claude Code](https://claude.ai/code/session_018gcsCQbuTMsyFWv874p25Q)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/23471?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -63,3 +63,10 @@ screenshots/
|
||||
|
||||
# local graphify knowledge-graph output (never commit)
|
||||
**/graphify-out/
|
||||
|
||||
# Local scratch scripts
|
||||
/.verify*.mjs
|
||||
/.shot*.mjs
|
||||
/.diag*.mjs
|
||||
/.compare*.mjs
|
||||
/.narrow*.mjs
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
</script>
|
||||
<!-- END: Twenty Config -->
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content"
|
||||
/>
|
||||
<script type="module">
|
||||
const disableInputAutoZoom = () => {
|
||||
const viewportMetadata = document.querySelector('meta[name=viewport]');
|
||||
@@ -45,7 +48,7 @@
|
||||
if (viewportMetadata !== null) {
|
||||
viewportMetadata.setAttribute(
|
||||
'content',
|
||||
'width=device-width, initial-scale=1.0, maximum-scale=1.0',
|
||||
'width=device-width, initial-scale=1.0, maximum-scale=1.0, interactive-widget=resizes-content',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
+2
@@ -12,11 +12,13 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedTimelineCalendarEvents } from '~/testing/mock-data/timeline-calendar-events';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof CalendarEventsCard> = {
|
||||
title: 'Modules/Activities/Calendar/CalendarEventsCard',
|
||||
component: CalendarEventsCard,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ComponentDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
+2
@@ -10,11 +10,13 @@ import { PageLayoutType } from '~/generated-metadata/graphql';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { mockedTimelineActivityRecords } from '~/testing/mock-data/generated/data/timelineActivities/mock-timelineActivities-data';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof TimelineCard> = {
|
||||
title: 'Modules/TimelineActivities/TimelineCard',
|
||||
component: TimelineCard,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ComponentDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
+2
@@ -5,11 +5,13 @@ import { EventCardCalendarEvent } from '@/activities/timeline-activities/rows/ca
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof EventCardCalendarEvent> = {
|
||||
title: 'Modules/TimelineActivities/Rows/CalendarEvent/EventCardCalendarEvent',
|
||||
component: EventCardCalendarEvent,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ComponentDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
+2
@@ -8,11 +8,13 @@ import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof EventCardMessage> = {
|
||||
title: 'Modules/TimelineActivities/Rows/Message/EventCardMessage',
|
||||
component: EventCardMessage,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ComponentDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
@@ -37,12 +37,13 @@ const StyledInputArea = styled.div<{ isMobile: boolean }>`
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
margin-top: auto;
|
||||
padding-block: ${({ isMobile }) =>
|
||||
isMobile ? '0' : themeCssVariables.spacing[3]};
|
||||
padding-inline: ${themeCssVariables.spacing[3]};
|
||||
`;
|
||||
|
||||
const StyledInputBox = styled.div`
|
||||
const StyledInputBox = styled.div<{ isMobile: boolean }>`
|
||||
background-color: ${themeCssVariables.background.transparent.lighter};
|
||||
border: 1px solid ${themeCssVariables.border.color.medium};
|
||||
border-radius: ${themeCssVariables.border.radius.sm};
|
||||
@@ -50,7 +51,7 @@ const StyledInputBox = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
min-height: 140px;
|
||||
min-height: ${({ isMobile }) => (isMobile ? '88px' : '140px')};
|
||||
padding: ${themeCssVariables.spacing[2]};
|
||||
width: 100%;
|
||||
|
||||
@@ -60,7 +61,7 @@ const StyledInputBox = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledEditorWrapper = styled.div`
|
||||
const StyledEditorWrapper = styled.div<{ isMobile: boolean }>`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
@@ -75,8 +76,8 @@ const StyledEditorWrapper = styled.div`
|
||||
font-size: ${themeCssVariables.font.size.md};
|
||||
font-weight: ${themeCssVariables.font.weight.regular};
|
||||
line-height: 16px;
|
||||
max-height: 320px;
|
||||
min-height: 48px;
|
||||
max-height: ${({ isMobile }) => (isMobile ? '160px' : '320px')};
|
||||
min-height: ${({ isMobile }) => (isMobile ? '36px' : '48px')};
|
||||
outline: none;
|
||||
overflow-y: auto;
|
||||
padding: 0;
|
||||
@@ -167,8 +168,8 @@ export const AiChatEditorSection = () => {
|
||||
{isDefined(pendingQuestion) ? (
|
||||
<AiChatQuestionCard pendingQuestion={pendingQuestion} />
|
||||
) : (
|
||||
<StyledInputBox>
|
||||
<StyledEditorWrapper>
|
||||
<StyledInputBox isMobile={isMobile}>
|
||||
<StyledEditorWrapper isMobile={isMobile}>
|
||||
<EditorContent editor={editor} />
|
||||
</StyledEditorWrapper>
|
||||
<StyledButtonsContainer>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { agentChatMessagesLoadingState } from '@/ai/states/agentChatMessagesLoad
|
||||
import { agentChatThreadsLoadingState } from '@/ai/states/agentChatThreadsLoadingState';
|
||||
import { currentAiChatThreadState } from '@/ai/states/currentAiChatThreadState';
|
||||
import { skipMessagesSkeletonUntilLoadedState } from '@/ai/states/skipMessagesSkeletonUntilLoadedState';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue';
|
||||
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
@@ -18,7 +19,6 @@ const StyledEmptyState = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
@@ -46,13 +46,15 @@ export const AiChatEmptyState = ({ editor }: AiChatEmptyStateProps) => {
|
||||
agentChatHasMessageComponentSelector,
|
||||
);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const isOnNewChatSlot =
|
||||
currentAiChatThread === AGENT_CHAT_NEW_THREAD_DRAFT_KEY;
|
||||
const skeletonShowing =
|
||||
(agentChatThreadsLoading && isOnNewChatSlot) ||
|
||||
(agentChatMessagesLoading && !skipMessagesSkeletonUntilLoaded);
|
||||
const shouldRender =
|
||||
!hasMessages && !isDefined(agentChatError) && !skeletonShowing;
|
||||
!isMobile && !hasMessages && !isDefined(agentChatError) && !skeletonShowing;
|
||||
|
||||
if (!shouldRender) {
|
||||
return null;
|
||||
|
||||
+2
-8
@@ -1,5 +1,5 @@
|
||||
import { type Editor } from '@tiptap/react';
|
||||
import { useEffect } from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
import { shouldFocusChatEditorState } from '@/ai/states/shouldFocusChatEditorState';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
@@ -15,19 +15,13 @@ export const AiChatEditorFocusEffect = ({
|
||||
shouldFocusChatEditorState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
useLayoutEffect(() => {
|
||||
if (!shouldFocusChatEditor || !editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rafId = requestAnimationFrame(() => {
|
||||
editor.commands.focus('end');
|
||||
setShouldFocusChatEditor(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(rafId);
|
||||
};
|
||||
}, [shouldFocusChatEditor, editor, setShouldFocusChatEditor]);
|
||||
|
||||
return null;
|
||||
|
||||
+2
@@ -30,6 +30,7 @@ import { mockedCompanyRecords } from '~/testing/mock-data/generated/data/compani
|
||||
import { getMockFieldMetadataItemOrThrow } from '~/testing/utils/getMockFieldMetadataItemOrThrow';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
import { getFieldInputEventContextProviderWithJestMocks } from './utils/getFieldInputEventContextProviderWithJestMocks';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const personMetadata = getMockObjectMetadataItemOrThrow('person');
|
||||
const companyMetadata = getMockObjectMetadataItemOrThrow('company');
|
||||
@@ -145,6 +146,7 @@ const meta: Meta = {
|
||||
onCancel: { control: false },
|
||||
},
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
clearMocksDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
+2
@@ -25,6 +25,7 @@ import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentTyp
|
||||
import { RelationType } from '~/generated-metadata/graphql';
|
||||
import { getMockFieldMetadataItemOrThrow } from '~/testing/utils/getMockFieldMetadataItemOrThrow';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const personMetadata = getMockObjectMetadataItemOrThrow('person');
|
||||
const companyMetadata = getMockObjectMetadataItemOrThrow('company');
|
||||
@@ -125,6 +126,7 @@ const meta: Meta = {
|
||||
component: RelationOneToManyFieldInputWithContext,
|
||||
args: {},
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
FileUploadDecorator,
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorato
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { RootDecorator } from '~/testing/decorators/RootDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const UPDATE_MANY_COMPANIES_MUTATION = gql`
|
||||
mutation UpdateManyCompanies(
|
||||
@@ -72,6 +73,7 @@ const meta: Meta<typeof UpdateMultipleRecordsContainer> = {
|
||||
'Modules/ObjectRecord/RecordUpdateMultiple/Components/UpdateMultipleRecordsContainer',
|
||||
component: UpdateMultipleRecordsContainer,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
(Story) => (
|
||||
<ApolloCoreClientContext.Provider value={mockApolloCoreClient}>
|
||||
<CommandMenuContext.Provider
|
||||
|
||||
+2
@@ -4,12 +4,14 @@ import { SettingsAccountsCalendarChannelsGeneral } from '@/settings/accounts/com
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof SettingsAccountsCalendarChannelsGeneral> = {
|
||||
title:
|
||||
'Modules/Settings/Accounts/CalendarChannels/SettingsAccountsCalendarChannelsGeneral',
|
||||
component: SettingsAccountsCalendarChannelsGeneral,
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
ComponentDecorator,
|
||||
ObjectMetadataItemsDecorator,
|
||||
SnackBarDecorator,
|
||||
|
||||
@@ -22,6 +22,7 @@ const StyledSidePanelContent = styled.div`
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
`;
|
||||
|
||||
export const SidePanelRouter = () => {
|
||||
|
||||
@@ -55,9 +55,13 @@ export const SidePanelToggleButton = () => {
|
||||
({ page }) => COMMAND_MENU_SIDE_PANEL_PAGES.includes(page),
|
||||
);
|
||||
|
||||
const isCoveredBySidePanelOnMobile =
|
||||
isMobile && isSidePanelOpened && !alignWithSidePanelTopBar;
|
||||
|
||||
const shouldHideButton =
|
||||
isCommandMenuOpened ||
|
||||
(isSidePanelOpened && hasCommandMenuPageInNavigationStack);
|
||||
(isSidePanelOpened && hasCommandMenuPageInNavigationStack) ||
|
||||
isCoveredBySidePanelOnMobile;
|
||||
|
||||
if (shouldHideButton) {
|
||||
return null;
|
||||
|
||||
+68
-1
@@ -4,6 +4,7 @@ import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { createStore, Provider as JotaiProvider } from 'jotai';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { isLayoutCustomizationModeEnabledState } from '@/layout-customization/states/isLayoutCustomizationModeEnabledState';
|
||||
import { SidePanelToggleButton } from '@/side-panel/components/SidePanelToggleButton';
|
||||
import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState';
|
||||
import { sidePanelNavigationStackState } from '@/side-panel/states/sidePanelNavigationStackState';
|
||||
@@ -15,9 +16,10 @@ import { SidePanelPages } from 'twenty-shared/types';
|
||||
import { IconDotsVertical } from 'twenty-ui/icon';
|
||||
|
||||
const mockAppTooltip = jest.fn();
|
||||
let mockIsMobile = false;
|
||||
|
||||
jest.mock('twenty-ui/utilities', () => ({
|
||||
useIsMobile: () => false,
|
||||
useIsMobile: () => mockIsMobile,
|
||||
getOsControlSymbol: () => '⌘',
|
||||
}));
|
||||
|
||||
@@ -36,6 +38,7 @@ const renderSidePanelToggleButton = ({
|
||||
sidePanelNavigationStack = [],
|
||||
sidePanelSearch = '',
|
||||
sidePanelSearchObjectFilter = null,
|
||||
isLayoutCustomizationModeEnabled = false,
|
||||
}: {
|
||||
isSidePanelOpened?: boolean;
|
||||
sidePanelPage?: SidePanelPages;
|
||||
@@ -47,6 +50,7 @@ const renderSidePanelToggleButton = ({
|
||||
}>;
|
||||
sidePanelSearch?: string;
|
||||
sidePanelSearchObjectFilter?: string | null;
|
||||
isLayoutCustomizationModeEnabled?: boolean;
|
||||
} = {}) => {
|
||||
const store = createStore();
|
||||
|
||||
@@ -55,6 +59,10 @@ const renderSidePanelToggleButton = ({
|
||||
store.set(sidePanelNavigationStackState.atom, sidePanelNavigationStack);
|
||||
store.set(sidePanelSearchState.atom, sidePanelSearch);
|
||||
store.set(sidePanelSearchObjectFilterState.atom, sidePanelSearchObjectFilter);
|
||||
store.set(
|
||||
isLayoutCustomizationModeEnabledState.atom,
|
||||
isLayoutCustomizationModeEnabled,
|
||||
);
|
||||
|
||||
render(
|
||||
<I18nProvider i18n={i18n}>
|
||||
@@ -77,6 +85,7 @@ const renderSidePanelToggleButton = ({
|
||||
describe('SidePanelToggleButton', () => {
|
||||
beforeEach(() => {
|
||||
mockAppTooltip.mockClear();
|
||||
mockIsMobile = false;
|
||||
});
|
||||
|
||||
it('opens the command menu when the side panel is closed', () => {
|
||||
@@ -158,6 +167,64 @@ describe('SidePanelToggleButton', () => {
|
||||
expect(screen.getByTestId('page-header-side-panel-button')).toBeVisible();
|
||||
});
|
||||
|
||||
it('hides the navbar command menu button on mobile while the side panel is open', () => {
|
||||
mockIsMobile = true;
|
||||
|
||||
renderSidePanelToggleButton({
|
||||
isSidePanelOpened: true,
|
||||
sidePanelPage: SidePanelPages.AskAI,
|
||||
sidePanelNavigationStack: [
|
||||
{
|
||||
page: SidePanelPages.AskAI,
|
||||
pageTitle: 'Ask AI',
|
||||
pageIcon: IconDotsVertical,
|
||||
pageId: 'ask-ai',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.queryByTestId('page-header-side-panel-button'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('keeps the navbar command menu button on mobile in layout customization mode', () => {
|
||||
mockIsMobile = true;
|
||||
|
||||
renderSidePanelToggleButton({
|
||||
isSidePanelOpened: true,
|
||||
sidePanelPage: SidePanelPages.AskAI,
|
||||
isLayoutCustomizationModeEnabled: true,
|
||||
sidePanelNavigationStack: [
|
||||
{
|
||||
page: SidePanelPages.AskAI,
|
||||
pageTitle: 'Ask AI',
|
||||
pageIcon: IconDotsVertical,
|
||||
pageId: 'ask-ai',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('page-header-side-panel-button')).toBeVisible();
|
||||
});
|
||||
|
||||
it('keeps the navbar command menu button on desktop while the AI chat is open', () => {
|
||||
renderSidePanelToggleButton({
|
||||
isSidePanelOpened: true,
|
||||
sidePanelPage: SidePanelPages.AskAI,
|
||||
sidePanelNavigationStack: [
|
||||
{
|
||||
page: SidePanelPages.AskAI,
|
||||
pageTitle: 'Ask AI',
|
||||
pageIcon: IconDotsVertical,
|
||||
pageId: 'ask-ai',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('page-header-side-panel-button')).toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the command menu keyboard shortcut in the tooltip', () => {
|
||||
renderSidePanelToggleButton();
|
||||
|
||||
|
||||
+5
@@ -41,6 +41,11 @@ jest.mock(
|
||||
}),
|
||||
);
|
||||
|
||||
const mockNavigateApp = jest.fn();
|
||||
jest.mock('~/hooks/useNavigateApp', () => ({
|
||||
useNavigateApp: () => mockNavigateApp,
|
||||
}));
|
||||
|
||||
const calendarEventMockObjectMetadataItem =
|
||||
getTestEnrichedObjectMetadataItemsMock().find(
|
||||
(item) => item.nameSingular === CoreObjectNameSingular.CalendarEvent,
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorato
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getWorkflowNodeIdMock } from '~/testing/mock-data/workflow';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const meta: Meta<typeof WorkflowStepFilterBuilder> = {
|
||||
title: 'Modules/Workflow/Filters/WorkflowStepFilterBuilder',
|
||||
@@ -26,6 +27,7 @@ const meta: Meta<typeof WorkflowStepFilterBuilder> = {
|
||||
onFilterSettingsUpdate: fn(),
|
||||
},
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
(Story) => (
|
||||
<WorkflowStepBody rowGap={themeCssVariables.spacing[0]}>
|
||||
<Story />
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const STEP_FILTER_GROUP: StepFilterGroup = {
|
||||
id: 'filter-group-1',
|
||||
@@ -40,6 +41,7 @@ const meta: Meta<typeof WorkflowStepFilterColumn> = {
|
||||
stepFilterIndex: 0,
|
||||
},
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
WorkflowStepActionDrawerDecorator,
|
||||
WorkflowStepDecorator,
|
||||
ComponentDecorator,
|
||||
|
||||
+2
@@ -8,6 +8,7 @@ import { WorkflowStepActionDrawerDecorator } from '~/testing/decorators/Workflow
|
||||
import { WorkflowStepDecorator } from '~/testing/decorators/WorkflowStepDecorator';
|
||||
import { WorkspaceDecorator } from '~/testing/decorators/WorkspaceDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator';
|
||||
|
||||
const TEXT_FILTER: StepFilter = {
|
||||
id: 'filter-1',
|
||||
@@ -39,6 +40,7 @@ const meta: Meta<typeof WorkflowStepFilterValueInput> = {
|
||||
stepFilter: TEXT_FILTER,
|
||||
},
|
||||
decorators: [
|
||||
MemoryRouterDecorator,
|
||||
WorkflowStepActionDrawerDecorator,
|
||||
WorkflowStepDecorator,
|
||||
ComponentDecorator,
|
||||
|
||||
Reference in New Issue
Block a user