Skip to content

Commit

Permalink
fix(SingleEntitySelectMenuItems): extract Add New button from entit…
Browse files Browse the repository at this point in the history
…iesToSelect (#8474)

# Description
Closes #8169

Extract Add New button from entitiesToSelect and add it as a separate
element .
There doesn't seem to be a point in having Add New as part of a list, it
seems better off in its own component, apart from list items

## Rationale
There already is #8353 addressing the same issue, but it seems it
doesn't really remove the duplicate "Add New" in the list, leaving a
duplicate "Add New" in `SingleEntitySelect`

---------

Co-authored-by: Félix Malfait <[email protected]>
  • Loading branch information
nicolasrouanne and FelixMalfait authored Nov 16, 2024
1 parent 9b2853b commit dc42315
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,13 @@ export const MultiRecordSelect = ({
<DropdownMenu ref={containerRef} data-select-disable>
{dropdownPlacement?.includes('end') && (
<>
<DropdownMenuItemsContainer>
{createNewButton}
</DropdownMenuItemsContainer>
{isDefined(onCreate) && (
<DropdownMenuItemsContainer>
{createNewButton}
</DropdownMenuItemsContainer>
)}
<DropdownMenuSeparator />
{results}
{objectRecordsIdsMultiSelect?.length > 0 && results}
{recordMultiSelectIsLoading && !relationPickerSearchFilter && (
<>
<DropdownMenuSkeletonItem />
Expand All @@ -171,13 +173,11 @@ export const MultiRecordSelect = ({
<DropdownMenuSeparator />
</>
)}
{results}
{objectRecordsIdsMultiSelect?.length > 0 && results}
{objectRecordsIdsMultiSelect?.length > 0 && (
<DropdownMenuSeparator />
)}
<DropdownMenuItemsContainer>
{createNewButton}
</DropdownMenuItemsContainer>
{isDefined(onCreate) && <div>{createNewButton}</div>}
</>
)}
</DropdownMenu>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { isNonEmptyString } from '@sniptt/guards';
import { Fragment, useRef } from 'react';
import { useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { IconComponent, IconPlus, MenuItemSelect } from 'twenty-ui';
import { IconComponent, MenuItemSelect } from 'twenty-ui';

import { SelectableMenuItemSelect } from '@/object-record/relation-picker/components/SelectableMenuItemSelect';
import { SINGLE_ENTITY_SELECT_BASE_LIST } from '@/object-record/relation-picker/constants/SingleEntitySelectBaseList';
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
Expand All @@ -26,8 +24,6 @@ export type SingleEntitySelectMenuItemsProps = {
onCancel?: () => void;
onEntitySelected: (entity?: EntityForSelect) => void;
selectedEntity?: EntityForSelect;
onCreate?: () => void;
showCreateButton?: boolean;
SelectAllIcon?: IconComponent;
selectAllLabel?: string;
isAllEntitySelected?: boolean;
Expand All @@ -46,8 +42,6 @@ export const SingleEntitySelectMenuItems = ({
onCancel,
onEntitySelected,
selectedEntity,
onCreate,
showCreateButton,
SelectAllIcon,
selectAllLabel,
isAllEntitySelected,
Expand All @@ -59,14 +53,6 @@ export const SingleEntitySelectMenuItems = ({
}: SingleEntitySelectMenuItemsProps) => {
const containerRef = useRef<HTMLDivElement>(null);

const createNewRecord = showCreateButton
? {
__typename: '',
id: 'add-new',
name: 'Add New',
}
: null;

const selectNone = emptyLabel
? {
__typename: '',
Expand All @@ -88,7 +74,6 @@ export const SingleEntitySelectMenuItems = ({
selectNone,
selectedEntity,
...entitiesToSelect,
createNewRecord,
].filter(
(entity): entity is EntityForSelect =>
isDefined(entity) && isNonEmptyString(entity.name),
Expand All @@ -98,10 +83,6 @@ export const SingleEntitySelectMenuItems = ({
SINGLE_ENTITY_SELECT_BASE_LIST,
);

const isSelectedAddNewButton = useRecoilValue(
isSelectedItemIdSelector('add-new'),
);

const isSelectedSelectNoneButton = useRecoilValue(
isSelectedItemIdSelector('select-none'),
);
Expand Down Expand Up @@ -129,14 +110,10 @@ export const SingleEntitySelectMenuItems = ({
selectableItemIdArray={selectableItemIds}
hotkeyScope={hotkeyScope}
onEnter={(itemId) => {
if (itemId === 'add-new' && showCreateButton === true) {
onCreate?.();
} else {
const entityIndex = entitiesInDropdown.findIndex(
(entity) => entity.id === itemId,
);
onEntitySelected(entitiesInDropdown[entityIndex]);
}
const entityIndex = entitiesInDropdown.findIndex(
(entity) => entity.id === itemId,
);
onEntitySelected(entitiesInDropdown[entityIndex]);
resetSelectedItem();
}}
>
Expand All @@ -146,32 +123,10 @@ export const SingleEntitySelectMenuItems = ({
) : entitiesInDropdown.length === 0 &&
!isAllEntitySelectShown &&
!loading ? (
<>
{entitiesToSelect.length > 0 && <DropdownMenuSeparator />}
<CreateNewButton
key="add-new"
onClick={onCreate}
LeftIcon={IconPlus}
text="Add New"
hovered={isSelectedAddNewButton}
/>
</>
<></>
) : (
entitiesInDropdown?.map((entity) => {
switch (entity.id) {
case 'add-new': {
return (
<Fragment key={entity.id}>
{entitiesToSelect.length > 0 && <DropdownMenuSeparator />}
<CreateNewButton
onClick={onCreate}
LeftIcon={IconPlus}
text="Add New"
hovered={isSelectedAddNewButton}
/>
</Fragment>
);
}
case 'select-none': {
return (
emptyLabel && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import {
} from '@/object-record/relation-picker/components/SingleEntitySelectMenuItems';
import { useEntitySelectSearch } from '@/object-record/relation-picker/hooks/useEntitySelectSearch';
import { useRelationPickerEntitiesOptions } from '@/object-record/relation-picker/hooks/useRelationPickerEntitiesOptions';
import { CreateNewButton } from '@/ui/input/relation-picker/components/CreateNewButton';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { Placement } from '@floating-ui/react';
import { IconPlus } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';

Expand Down Expand Up @@ -49,21 +52,13 @@ export const SingleEntitySelectMenuItemsWithSearch = ({
excludedRelationRecordIds,
});

const showCreateButton = isDefined(onCreate);

let onCreateWithInput = undefined;

if (isDefined(onCreate)) {
onCreateWithInput = () => {
if (onCreate.length > 0) {
(onCreate as (searchInput?: string) => void)(
relationPickerSearchFilter,
);
} else {
(onCreate as () => void)();
}
};
}
const createNewButton = isDefined(onCreate) && (
<CreateNewButton
onClick={() => onCreate?.(relationPickerSearchFilter)}
LeftIcon={IconPlus}
text="Add New"
/>
);

const results = (
<SingleEntitySelectMenuItems
Expand All @@ -76,14 +71,12 @@ export const SingleEntitySelectMenuItemsWithSearch = ({
}
shouldSelectEmptyOption={selectedRelationRecordIds?.length === 0}
hotkeyScope={relationPickerScopeId}
onCreate={onCreateWithInput}
isFiltered={!!relationPickerSearchFilter}
{...{
EmptyIcon,
emptyLabel,
onCancel,
onEntitySelected,
showCreateButton,
}}
/>
);
Expand All @@ -92,7 +85,11 @@ export const SingleEntitySelectMenuItemsWithSearch = ({
<>
{dropdownPlacement?.includes('end') && (
<>
{results}
<DropdownMenuItemsContainer>
{createNewButton}
</DropdownMenuItemsContainer>
{entities.entitiesToSelect.length > 0 && <DropdownMenuSeparator />}
{entities.entitiesToSelect.length > 0 && results}
<DropdownMenuSeparator />
</>
)}
Expand All @@ -101,7 +98,15 @@ export const SingleEntitySelectMenuItemsWithSearch = ({
isUndefinedOrNull(dropdownPlacement)) && (
<>
<DropdownMenuSeparator />
{results}
{entities.entitiesToSelect.length > 0 && results}
{entities.entitiesToSelect.length > 0 && isDefined(onCreate) && (
<DropdownMenuSeparator />
)}
{isDefined(onCreate) && (
<DropdownMenuItemsContainer>
{createNewButton}
</DropdownMenuItemsContainer>
)}
</>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
size,
useFloating,
} from '@floating-ui/react';
import { MouseEvent, ReactNode, useRef } from 'react';
import { MouseEvent, ReactNode, useEffect, useRef } from 'react';
import { Keys } from 'react-hotkeys-hook';
import { Key } from 'ts-key-enum';

Expand Down Expand Up @@ -65,8 +65,13 @@ export const Dropdown = ({
}: DropdownProps) => {
const containerRef = useRef<HTMLDivElement>(null);

const { isDropdownOpen, toggleDropdown, closeDropdown, dropdownWidth } =
useDropdown(dropdownId);
const {
isDropdownOpen,
toggleDropdown,
closeDropdown,
dropdownWidth,
setDropdownPlacement,
} = useDropdown(dropdownId);

const offsetMiddlewares = [];

Expand All @@ -78,7 +83,7 @@ export const Dropdown = ({
offsetMiddlewares.push(offset({ mainAxis: dropdownOffset.y }));
}

const { refs, floatingStyles } = useFloating({
const { refs, floatingStyles, placement } = useFloating({
placement: dropdownPlacement,
middleware: [
flip(),
Expand All @@ -100,6 +105,10 @@ export const Dropdown = ({
strategy: dropdownStrategy,
});

useEffect(() => {
setDropdownPlacement(placement);
}, [placement, setDropdownPlacement]);

const handleHotkeyTriggered = () => {
toggleDropdown();
};
Expand Down

0 comments on commit dc42315

Please sign in to comment.