Files
twenty/packages/twenty-front/src/modules/views/components/ViewGroupsVisibilityDropdownSection.tsx
Jérémy M e8d96cfd10 feat: view groups (#7176)
Fix #4244 and #4356

This pull request introduces the new "view groups" capability, enabling
the reordering, hiding, and showing of columns in Kanban mode. The core
enhancement includes the addition of a new entity named `ViewGroup`,
which manages column behaviors and interactions.

#### Key Changes:
1. **ViewGroup Entity**:  
The newly added `ViewGroup` entity is responsible for handling the
organization and state of columns.
This includes:
   - The ability to reorder columns.
- The option to hide or show specific columns based on user preferences.

#### Conclusion:
This PR adds a significant new feature that enhances the flexibility of
Kanban views through the `ViewGroup` entity.
We'll later add the view group logic to table view too.

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2024-10-24 15:38:52 +02:00

193 lines
6.9 KiB
TypeScript

import {
DropResult,
OnDragEndResponder,
ResponderProvided,
} from '@hello-pangea/dnd';
import { useRef } from 'react';
import { IconEye, IconEyeOff, Tag } from 'twenty-ui';
import {
RecordGroupDefinition,
RecordGroupDefinitionType,
} from '@/object-record/record-group/types/RecordGroupDefinition';
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 { MenuItemDraggable } from '@/ui/navigation/menu-item/components/MenuItemDraggable';
import { isDefined } from '~/utils/isDefined';
type ViewGroupsVisibilityDropdownSectionProps = {
viewGroups: RecordGroupDefinition[];
isDraggable: boolean;
onDragEnd?: OnDragEndResponder;
onVisibilityChange: (viewGroup: RecordGroupDefinition) => void;
title: string;
showSubheader: boolean;
showDragGrip: boolean;
};
export const ViewGroupsVisibilityDropdownSection = ({
viewGroups,
isDraggable,
onDragEnd,
onVisibilityChange,
title,
showSubheader = true,
showDragGrip,
}: ViewGroupsVisibilityDropdownSectionProps) => {
const handleOnDrag = (result: DropResult, provided: ResponderProvided) => {
onDragEnd?.(result, provided);
};
const getIconButtons = (index: number, viewGroup: RecordGroupDefinition) => {
const iconButtons = [
{
Icon: viewGroup.isVisible ? IconEyeOff : IconEye,
onClick: () => onVisibilityChange(viewGroup),
},
].filter(isDefined);
return iconButtons.length ? iconButtons : undefined;
};
const noValueViewGroups =
viewGroups.filter(
(viewGroup) => viewGroup.type === RecordGroupDefinitionType.NoValue,
) ?? [];
const viewGroupsWithoutNoValueGroups = viewGroups.filter(
(viewGroup) => viewGroup.type !== RecordGroupDefinitionType.NoValue,
);
const ref = useRef<HTMLDivElement>(null);
return (
<div ref={ref}>
{showSubheader && (
<StyledDropdownMenuSubheader>{title}</StyledDropdownMenuSubheader>
)}
<DropdownMenuItemsContainer>
{!!viewGroups.length && (
<>
{!isDraggable ? (
viewGroupsWithoutNoValueGroups.map(
(viewGroup, viewGroupIndex) => (
<MenuItemDraggable
key={viewGroup.id}
text={
<Tag
variant={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? viewGroup.color
: 'transparent'
}
text={viewGroup.title}
weight={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? 'regular'
: 'medium'
}
/>
}
iconButtons={getIconButtons(viewGroupIndex, viewGroup)}
accent={showDragGrip ? 'placeholder' : 'default'}
showGrip={showDragGrip}
isDragDisabled={!isDraggable}
/>
),
)
) : (
<DraggableList
onDragEnd={handleOnDrag}
draggableItems={
<>
{viewGroupsWithoutNoValueGroups.map(
(viewGroup, viewGroupIndex) => (
<DraggableItem
key={viewGroup.id}
draggableId={viewGroup.id}
index={viewGroupIndex + 1}
itemComponent={
<MenuItemDraggable
key={viewGroup.id}
text={
<Tag
variant={
viewGroup.type !==
RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
viewGroup.type !==
RecordGroupDefinitionType.NoValue
? viewGroup.color
: 'transparent'
}
text={viewGroup.title}
weight={
viewGroup.type !==
RecordGroupDefinitionType.NoValue
? 'regular'
: 'medium'
}
/>
}
iconButtons={getIconButtons(
viewGroupIndex,
viewGroup,
)}
accent={showDragGrip ? 'placeholder' : 'default'}
showGrip={showDragGrip}
isDragDisabled={!isDraggable}
/>
}
/>
),
)}
</>
}
/>
)}
{noValueViewGroups.map((viewGroup) => (
<MenuItemDraggable
key={viewGroup.id}
text={
<Tag
variant={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? viewGroup.color
: 'transparent'
}
text={viewGroup.title}
weight={
viewGroup.type !== RecordGroupDefinitionType.NoValue
? 'regular'
: 'medium'
}
/>
}
accent={showDragGrip ? 'placeholder' : 'default'}
showGrip={true}
isDragDisabled={true}
isHoverDisabled
/>
))}
</>
)}
</DropdownMenuItemsContainer>
</div>
);
};