Chore(front): Create Storybook tests for the DropdownMenu component (#2157)

* Chore(front): Create Storybook tests for the DropdownMenu component

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>

* Fix the tests

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>

* Simplify Dropdown

* Remove console.log

---------

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-twenty
2023-10-20 22:19:43 +03:00
committed by GitHub
parent eea7470571
commit dee9807eb3
41 changed files with 634 additions and 674 deletions

View File

@ -1,4 +1,4 @@
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@ -19,7 +19,7 @@ export const FilterDropdownEntitySelect = () => {
return (
<>
<StyledDropdownMenuSeparator />
<DropdownMenuSeparator />
<RecoilScope>
{filterDefinitionUsedInDropdown.entitySelectComponent}
</RecoilScope>

View File

@ -1,10 +1,11 @@
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { FilterDropdownId } from '../constants/FilterDropdownId';
import { MultipleFiltersButton } from './MultipleFiltersButton';
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
type MultipleFiltersDropdownButtonProps = {
hotkeyScope: HotkeyScope;
@ -14,11 +15,13 @@ export const MultipleFiltersDropdownButton = ({
hotkeyScope,
}: MultipleFiltersDropdownButtonProps) => {
return (
<ViewBarDropdownButton
dropdownId={FilterDropdownId}
buttonComponent={<MultipleFiltersButton />}
dropdownComponents={<MultipleFiltersDropdownContent />}
dropdownHotkeyScope={hotkeyScope}
/>
<DropdownScope dropdownScopeId={FilterDropdownId}>
<Dropdown
clickableComponent={<MultipleFiltersButton />}
dropdownComponents={<MultipleFiltersDropdownContent />}
dropdownHotkeyScope={hotkeyScope}
dropdownOffset={{ y: 8 }}
/>
</DropdownScope>
);
};

View File

@ -1,5 +1,4 @@
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useViewBarContext } from '../hooks/useViewBarContext';
@ -35,36 +34,34 @@ export const MultipleFiltersDropdownContent = () => {
);
return (
<StyledDropdownMenu>
<>
{!filterDefinitionUsedInDropdown ? (
<FilterDropdownFilterSelect />
) : isFilterDropdownOperandSelectUnfolded ? (
<FilterDropdownOperandSelect />
) : (
selectedOperandInDropdown && (
<>
<FilterDropdownOperandButton />
<StyledDropdownMenuSeparator />
{filterDefinitionUsedInDropdown.type === 'text' && (
<FilterDropdownTextSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'number' && (
<FilterDropdownNumberSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'date' && (
<FilterDropdownDateSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'entity' && (
<FilterDropdownEntitySearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'entity' && (
<FilterDropdownEntitySelect />
)}
</>
)
)}
</>
</StyledDropdownMenu>
<>
{!filterDefinitionUsedInDropdown ? (
<FilterDropdownFilterSelect />
) : isFilterDropdownOperandSelectUnfolded ? (
<FilterDropdownOperandSelect />
) : (
selectedOperandInDropdown && (
<>
<FilterDropdownOperandButton />
<DropdownMenuSeparator />
{filterDefinitionUsedInDropdown.type === 'text' && (
<FilterDropdownTextSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'number' && (
<FilterDropdownNumberSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'date' && (
<FilterDropdownDateSearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'entity' && (
<FilterDropdownEntitySearchInput />
)}
{filterDefinitionUsedInDropdown.type === 'entity' && (
<FilterDropdownEntitySelect />
)}
</>
)
)}
</>
);
};

View File

@ -2,8 +2,7 @@ import React from 'react';
import { useTheme } from '@emotion/react';
import { IconChevronDown } from '@/ui/display/icon/index';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuContainer } from '@/ui/layout/dropdown/components/DropdownMenuContainer';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@ -63,7 +62,7 @@ export const SingleEntityFilterDropdownButton = ({
return (
<DropdownScope dropdownScopeId="single-entity-filter-dropdown">
<DropdownMenu
<Dropdown
dropdownHotkeyScope={hotkeyScope}
dropdownOffset={{ x: 0, y: -28 }}
clickableComponent={
@ -84,10 +83,10 @@ export const SingleEntityFilterDropdownButton = ({
</StyledHeaderDropdownButton>
}
dropdownComponents={
<DropdownMenuContainer>
<>
<FilterDropdownEntitySearchInput />
<FilterDropdownEntitySelect />
</DropdownMenuContainer>
</>
}
/>
</DropdownScope>

View File

@ -3,11 +3,12 @@ import { produce } from 'immer';
import { IconChevronDown } from '@/ui/display/icon';
import { LightButton } from '@/ui/input/button/components/LightButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@ -19,8 +20,6 @@ import { sortsScopedState } from '../states/sortsScopedState';
import { SortDefinition } from '../types/SortDefinition';
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
export type SortDropdownButtonProps = {
hotkeyScope: HotkeyScope;
isPrimaryButton?: boolean;
@ -91,56 +90,58 @@ export const SortDropdownButton = ({
};
return (
<ViewBarDropdownButton
dropdownId={SortDropdownId}
dropdownHotkeyScope={hotkeyScope}
buttonComponent={
<LightButton
title="Sort"
active={isSortSelected}
onClick={handleButtonClick}
/>
}
dropdownComponents={
<StyledDropdownMenu>
{isSortDirectionMenuUnfolded ? (
<DropdownMenuItemsContainer>
{SORT_DIRECTIONS.map((sortOrder, index) => (
<MenuItem
key={index}
onClick={() => {
setSelectedSortDirection(sortOrder);
setIsSortDirectionMenuUnfolded(false);
}}
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
/>
))}
</DropdownMenuItemsContainer>
) : (
<>
<DropdownMenuHeader
EndIcon={IconChevronDown}
onClick={() => setIsSortDirectionMenuUnfolded(true)}
>
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
</DropdownMenuHeader>
<StyledDropdownMenuSeparator />
<DropdownScope dropdownScopeId={SortDropdownId}>
<Dropdown
dropdownHotkeyScope={hotkeyScope}
dropdownOffset={{ y: 8 }}
clickableComponent={
<LightButton
title="Sort"
active={isSortSelected}
onClick={handleButtonClick}
/>
}
dropdownComponents={
<>
{isSortDirectionMenuUnfolded ? (
<DropdownMenuItemsContainer>
{availableSorts.map((availableSort, index) => (
{SORT_DIRECTIONS.map((sortOrder, index) => (
<MenuItem
testId={`select-sort-${index}`}
key={index}
onClick={() => handleAddSort(availableSort)}
LeftIcon={availableSort.Icon}
text={availableSort.label}
onClick={() => {
setSelectedSortDirection(sortOrder);
setIsSortDirectionMenuUnfolded(false);
}}
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
/>
))}
</DropdownMenuItemsContainer>
</>
)}
</StyledDropdownMenu>
}
onClose={handleDropdownButtonClose}
></ViewBarDropdownButton>
) : (
<>
<DropdownMenuHeader
EndIcon={IconChevronDown}
onClick={() => setIsSortDirectionMenuUnfolded(true)}
>
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
</DropdownMenuHeader>
<DropdownMenuSeparator />
<DropdownMenuItemsContainer>
{availableSorts.map((availableSort, index) => (
<MenuItem
testId={`select-sort-${index}`}
key={index}
onClick={() => handleAddSort(availableSort)}
LeftIcon={availableSort.Icon}
text={availableSort.label}
/>
))}
</DropdownMenuItemsContainer>
</>
)}
</>
}
onClose={handleDropdownButtonClose}
/>
</DropdownScope>
);
};

View File

@ -14,7 +14,6 @@ import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { IconChevronDown, IconPlus } from '@/ui/display/icon';
import { Button } from '@/ui/input/button/components/Button';
import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup';
import { DropdownMenuContainer } from '@/ui/layout/dropdown/components/DropdownMenuContainer';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@ -126,15 +125,13 @@ export const UpdateViewButtonGroup = ({
</ButtonGroup>
{isDropdownOpen && (
<DropdownMenuContainer onClose={handleDropdownClose}>
<DropdownMenuItemsContainer>
<MenuItem
onClick={handleCreateViewButtonClick}
LeftIcon={IconPlus}
text="Create view"
/>
</DropdownMenuItemsContainer>
</DropdownMenuContainer>
<DropdownMenuItemsContainer>
<MenuItem
onClick={handleCreateViewButtonClick}
LeftIcon={IconPlus}
text="Create view"
/>
</DropdownMenuItemsContainer>
)}
</StyledContainer>
);

View File

@ -1,49 +0,0 @@
import { Keys } from 'react-hotkeys-hook';
import { Placement } from '@floating-ui/react';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
type ViewBarDropdownButtonProps = {
buttonComponent: JSX.Element | JSX.Element[];
dropdownComponents: JSX.Element | JSX.Element[];
dropdownId: string;
hotkey?: {
key: Keys;
scope: string;
};
dropdownHotkeyScope: HotkeyScope;
dropdownPlacement?: Placement;
onClickOutside?: () => void;
onClose?: () => void;
onOpen?: () => void;
};
export const ViewBarDropdownButton = ({
buttonComponent,
dropdownComponents,
dropdownId,
hotkey,
dropdownHotkeyScope,
dropdownPlacement = 'bottom-end',
onClickOutside,
onClose,
onOpen,
}: ViewBarDropdownButtonProps) => {
return (
<DropdownScope dropdownScopeId={dropdownId}>
<DropdownMenu
clickableComponent={buttonComponent}
dropdownComponents={dropdownComponents}
hotkey={hotkey}
dropdownHotkeyScope={dropdownHotkeyScope}
dropdownOffset={{ x: 0, y: 8 }}
dropdownPlacement={dropdownPlacement}
onClickOutside={onClickOutside}
onClose={onClose}
onOpen={onOpen}
/>
</DropdownScope>
);
};

View File

@ -24,11 +24,12 @@ import {
IconPlus,
IconTrash,
} from '@/ui/display/icon';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@ -41,8 +42,6 @@ import { ViewsDropdownId } from '../constants/ViewsDropdownId';
import { ViewBarContext } from '../contexts/ViewBarContext';
import { useRemoveView } from '../hooks/useRemoveView';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
font-weight: ${({ theme }) => theme.font.weight.regular};
`;
@ -159,56 +158,57 @@ export const ViewsDropdownButton = ({
};
return (
<ViewBarDropdownButton
dropdownId={ViewsDropdownId}
dropdownHotkeyScope={hotkeyScope}
buttonComponent={
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
<StyledViewIcon size={theme.icon.size.md} />
<StyledViewName>
{currentView?.name || defaultViewName}
</StyledViewName>
<StyledDropdownLabelAdornments>
· {entityCount} <IconChevronDown size={theme.icon.size.sm} />
</StyledDropdownLabelAdornments>
</StyledDropdownButtonContainer>
}
dropdownComponents={
<StyledDropdownMenu width={200}>
<DropdownMenuItemsContainer>
{views.map((view) => (
<DropdownScope dropdownScopeId={ViewsDropdownId}>
<Dropdown
dropdownHotkeyScope={hotkeyScope}
clickableComponent={
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
<StyledViewIcon size={theme.icon.size.md} />
<StyledViewName>
{currentView?.name || defaultViewName}
</StyledViewName>
<StyledDropdownLabelAdornments>
· {entityCount} <IconChevronDown size={theme.icon.size.sm} />
</StyledDropdownLabelAdornments>
</StyledDropdownButtonContainer>
}
dropdownComponents={
<>
<DropdownMenuItemsContainer>
{views.map((view) => (
<MenuItem
key={view.id}
iconButtons={[
{
Icon: IconPencil,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleEditViewButtonClick(event, view.id),
},
views.length > 1
? {
Icon: IconTrash,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleDeleteViewButtonClick(event, view.id),
}
: null,
].filter(assertNotNull)}
onClick={() => handleViewSelect(view.id)}
LeftIcon={IconList}
text={view.name}
/>
))}
</DropdownMenuItemsContainer>
<DropdownMenuSeparator />
<StyledBoldDropdownMenuItemsContainer>
<MenuItem
key={view.id}
iconButtons={[
{
Icon: IconPencil,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleEditViewButtonClick(event, view.id),
},
views.length > 1
? {
Icon: IconTrash,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleDeleteViewButtonClick(event, view.id),
}
: null,
].filter(assertNotNull)}
onClick={() => handleViewSelect(view.id)}
LeftIcon={IconList}
text={view.name}
onClick={handleAddViewButtonClick}
LeftIcon={IconPlus}
text="Add view"
/>
))}
</DropdownMenuItemsContainer>
<StyledDropdownMenuSeparator />
<StyledBoldDropdownMenuItemsContainer>
<MenuItem
onClick={handleAddViewButtonClick}
LeftIcon={IconPlus}
text="Add view"
/>
</StyledBoldDropdownMenuItemsContainer>
</StyledDropdownMenu>
}
/>
</StyledBoldDropdownMenuItemsContainer>
</>
}
/>
</DropdownScope>
);
};