4a4e65fe4a
# 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
154 lines
5.0 KiB
TypeScript
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,
|
|
)}
|
|
</>
|
|
);
|
|
};
|