Files
twenty/packages/twenty-front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx
T
Paul Rastoin 4a4e65fe4a [REFACTOR] Twenty UI multi barrel (#11301)
# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/591
Same than for `twenty-shared` made in
https://github.com/twentyhq/twenty/pull/11083.

## TODO
- [x] Manual migrate twenty-website twenty-ui imports

## What's next:
- Generate barrel and migration script factorization within own package
+ tests
- Refactoring using preconstruct ? TimeBox
- Lint circular dependencies
- Lint import from barrel and forbid them

### Preconstruct
We need custom rollup plugins addition, but preconstruct does not expose
its rollup configuration. It might be possible to handle this using the
babel overrides. But was a big tunnel.
We could give it a try afterwards ! ( allowing cjs interop and stuff
like that )
Stuck to vite lib app

Closed related PRs:
- https://github.com/twentyhq/twenty/pull/11294
- https://github.com/twentyhq/twenty/pull/11203
2025-04-03 09:47:55 +00:00

154 lines
5.0 KiB
TypeScript

import {
DropResult,
OnDragEndResponder,
ResponderProvided,
} from '@hello-pangea/dnd';
import { useState } from 'react';
import { createPortal } from 'react-dom';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { DraggableItem } from '@/ui/layout/draggable-list/components/DraggableItem';
import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableList';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenuSubheader } from '@/ui/layout/dropdown/components/StyledDropdownMenuSubheader';
import { groupArrayItemsBy } from '~/utils/array/groupArrayItemsBy';
import { isDefined } from 'twenty-shared/utils';
import {
AppTooltip,
IconEye,
IconEyeOff,
IconInfoCircle,
useIcons,
} from 'twenty-ui/display';
import { MenuItemDraggable } from 'twenty-ui/navigation';
type ViewFieldsVisibilityDropdownSectionProps = {
fields: Omit<ColumnDefinition<FieldMetadata>, 'size'>[];
isDraggable: boolean;
onDragEnd?: OnDragEndResponder;
onVisibilityChange: (
field: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
) => void;
title: string;
showSubheader: boolean;
showDragGrip: boolean;
};
export const ViewFieldsVisibilityDropdownSection = ({
fields,
isDraggable,
onDragEnd,
onVisibilityChange,
title,
showSubheader = true,
showDragGrip,
}: ViewFieldsVisibilityDropdownSectionProps) => {
const handleOnDrag = (result: DropResult, provided: ResponderProvided) => {
onDragEnd?.(result, provided);
};
const [openToolTipIndex, setOpenToolTipIndex] = useState<number>();
const handleInfoButtonClick = (index: number) => {
setOpenToolTipIndex(index === openToolTipIndex ? undefined : index);
};
const { getIcon } = useIcons();
const getIconButtons = (
index: number,
field: Omit<ColumnDefinition<FieldMetadata>, 'size' | 'position'>,
) => {
const iconButtons = [
field.infoTooltipContent
? {
Icon: IconInfoCircle,
onClick: () => handleInfoButtonClick(index),
isActive: openToolTipIndex === index,
}
: null,
field.isLabelIdentifier
? null
: {
Icon: field.isVisible ? IconEyeOff : IconEye,
onClick: () => onVisibilityChange(field),
},
].filter(isDefined);
return iconButtons.length ? iconButtons : undefined;
};
const { nonDraggableItems = [], draggableItems = [] } = isDraggable
? groupArrayItemsBy(fields, ({ isLabelIdentifier }) =>
isLabelIdentifier ? 'nonDraggableItems' : 'draggableItems',
)
: { nonDraggableItems: fields, draggableItems: [] };
return (
<>
{showSubheader && (
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
)}
<DropdownMenuItemsContainer>
{nonDraggableItems.map((field, fieldIndex) => (
<MenuItemDraggable
key={field.fieldMetadataId}
LeftIcon={getIcon(field.iconName)}
iconButtons={getIconButtons(fieldIndex, field)}
isTooltipOpen={openToolTipIndex === fieldIndex}
text={field.label}
className={`${title}-fixed-item-tooltip-anchor-${fieldIndex}`}
accent={showDragGrip ? 'placeholder' : 'default'}
showGrip={showDragGrip}
isDragDisabled
/>
))}
{!!draggableItems.length && (
<DraggableList
onDragEnd={handleOnDrag}
draggableItems={
<>
{draggableItems.map((field, index) => {
const fieldIndex = index + nonDraggableItems.length;
return (
<DraggableItem
key={field.fieldMetadataId}
draggableId={field.fieldMetadataId}
index={fieldIndex + 1}
itemComponent={
<MenuItemDraggable
key={field.fieldMetadataId}
LeftIcon={getIcon(field.iconName)}
iconButtons={getIconButtons(fieldIndex, field)}
isTooltipOpen={openToolTipIndex === fieldIndex}
text={field.label}
className={`${title}-draggable-item-tooltip-anchor-${fieldIndex}`}
showGrip
/>
}
/>
);
})}
</>
}
/>
)}
</DropdownMenuItemsContainer>
{isDefined(openToolTipIndex) &&
createPortal(
<AppTooltip
anchorSelect={`.${title}-${
isDraggable ? 'draggable' : 'fixed'
}-item-tooltip-anchor-${openToolTipIndex}`}
place="left"
content={fields[openToolTipIndex].infoTooltipContent}
hidden={false}
/>,
document.body,
)}
</>
);
};