Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4900 multi select field front implement expanded cells #5151

Merged
merged 52 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c9566d8
WIP: Use isHovered in fieldDisplay
martmull Apr 23, 2024
ebd95b2
Update design
martmull Apr 23, 2024
8fe7363
Add shrink
martmull Apr 24, 2024
cd3b1cd
Use width to compute hover
martmull Apr 24, 2024
accabe9
Simplify
martmull Apr 24, 2024
466bba9
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull Apr 24, 2024
63f4e33
Use dropdown for expanded cell
martmull Apr 25, 2024
0b02ba9
Update dropdown component
martmull Apr 25, 2024
07bec4a
Factorize
martmull Apr 26, 2024
5be6608
Fix dropdown for inline cell
martmull Apr 26, 2024
eadb24a
WIP: add default state
martmull Apr 26, 2024
1d48763
Fix soft focus
martmull Apr 26, 2024
cebc4b2
Inject children properties in parent
martmull Apr 26, 2024
4be93e9
Rename state
martmull Apr 26, 2024
9cb05af
Rename component
martmull Apr 26, 2024
fa10ac6
Factorize type
martmull Apr 26, 2024
fc610d4
Factorize Var
martmull Apr 26, 2024
cbdc290
Fix dropdown size
martmull Apr 26, 2024
8a8433c
Display when navigating with keyboard
martmull Apr 26, 2024
55b7519
Fix +number chip width
martmull Apr 26, 2024
784826e
Use expanded list in activities
martmull Apr 26, 2024
2f50fa8
Fix: Use expanded list in activities
martmull Apr 29, 2024
74e8298
Use expanded list in calendar
martmull Apr 29, 2024
0405af5
Fix multiworkspace
martmull Apr 29, 2024
d453ee9
WIP: fix force display hidden count
martmull Apr 29, 2024
60bda4e
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull Apr 29, 2024
1548766
Simplify
martmull Apr 30, 2024
fd3c37a
Make expandable list component function pure
martmull Apr 30, 2024
62d7733
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull Apr 30, 2024
2c69203
Move expandable list to proper place
martmull Apr 30, 2024
d09bbb3
Split components in two
martmull Apr 30, 2024
ee17e78
Move to proper place and fix imports
martmull Apr 30, 2024
4f5f3b2
Remove width for chip
martmull Apr 30, 2024
82bf06e
Create dedicated function to compute children properties
martmull May 1, 2024
1b3ae40
Remove useless parameter
martmull May 1, 2024
a00216b
Add tests
martmull May 1, 2024
e1db801
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull May 2, 2024
38014bf
Code review returns
martmull May 2, 2024
5cceba8
Disallow allowImportingTsExtensions
martmull May 2, 2024
0bdb6a3
Remove useless component
martmull May 2, 2024
50dd265
Remove ANIMATION DIV PROPS constant
martmull May 3, 2024
a84177a
Add story for expandableList
martmull May 3, 2024
409bcc7
Rename variable
martmull May 3, 2024
6046af9
Fix ci
martmull May 3, 2024
a3be163
Fix ci
martmull May 3, 2024
eb27698
Fix console error
martmull May 3, 2024
82732b0
Fix console error
martmull May 3, 2024
cb9a9ff
Fix test
martmull May 3, 2024
0a18062
Remove fix
martmull May 3, 2024
40cf4bf
Update test
martmull May 3, 2024
8bdec12
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull May 3, 2024
25a117e
Merge branch 'main' into 4900-multi-select-field-front-implement-expa…
martmull May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { useRef } from 'react';
import { useRef, useState } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { IconCheck, IconQuestionMark, IconX } from 'twenty-ui';
import { v4 } from 'uuid';

import { CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant';
import { ParticipantChip } from '@/activities/components/ParticipantChip';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { ExpandableList } from '@/ui/display/expandable-list/ExpandableList';
import { EllipsisDisplay } from '@/ui/field/display/components/EllipsisDisplay';
import { ExpandableList } from '@/ui/layout/expandable-list/ExpandableList';
import { isRightDrawerAnimationCompletedState } from '@/ui/layout/right-drawer/states/isRightDrawerAnimationCompleted.ts';

const StyledInlineCellBaseContainer = styled.div`
align-items: center;
Expand Down Expand Up @@ -55,6 +56,9 @@ const StyledLabelContainer = styled.div<{ width?: number }>`
font-size: ${({ theme }) => theme.font.size.sm};
width: ${({ width }) => width}px;
`;
const StyledDiv = styled.div`
max-width: 70%;
`;

export const CalendarEventParticipantsResponseStatusField = ({
responseStatus,
Expand All @@ -64,6 +68,9 @@ export const CalendarEventParticipantsResponseStatusField = ({
participants: CalendarEventParticipant[];
}) => {
const theme = useTheme();
const isRightDrawerAnimationCompleted = useRecoilValue(
isRightDrawerAnimationCompletedState,
);

const Icon = {
Yes: <IconCheck stroke={theme.icon.stroke.sm} />,
Expand All @@ -81,9 +88,9 @@ export const CalendarEventParticipantsResponseStatusField = ({
];

const participantsContainerRef = useRef<HTMLDivElement>(null);

const StyledChips = orderedParticipants.map((participant) => (
<ParticipantChip participant={participant} />
const [isHovered, setIsHovered] = useState(false);
const styledChips = orderedParticipants.map((participant, index) => (
<ParticipantChip key={index} participant={participant} />
));

return (
Expand All @@ -96,12 +103,21 @@ export const CalendarEventParticipantsResponseStatusField = ({
<EllipsisDisplay>{responseStatus}</EllipsisDisplay>
</StyledLabelContainer>
</StyledLabelAndIconContainer>

<ExpandableList
listItems={StyledChips}
id={v4()}
rootRef={participantsContainerRef}
/>
<StyledDiv
ref={participantsContainerRef}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{isRightDrawerAnimationCompleted && (
<ExpandableList
isHovered={isHovered}
reference={participantsContainerRef.current || undefined}
forceDisplayHiddenCount
>
{styledChips}
</ExpandableList>
)}
</StyledDiv>
</StyledInlineCellBaseContainer>
</StyledPropertyBox>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isRightDrawerAnimationCompletedState } from '@/ui/layout/right-drawer/states/isRightDrawerAnimationCompleted.ts';
import { isDefined } from '~/utils/isDefined';

const StyledPropertyBox = styled(PropertyBox)`
Expand All @@ -27,6 +28,10 @@ export const ActivityEditorFields = ({
}) => {
const { upsertActivity } = useUpsertActivity();

const isRightDrawerAnimationCompleted = useRecoilValue(
isRightDrawerAnimationCompletedState,
);

const getRecordFromCache = useGetRecordFromCache({
objectNameSingular: CoreObjectNameSingular.Activity,
});
Expand Down Expand Up @@ -93,11 +98,16 @@ export const ActivityEditorFields = ({
</AssigneeFieldContextProvider>
</>
)}
{ActivityTargetsContextProvider && isDefined(activityFromCache) && (
<ActivityTargetsContextProvider>
<ActivityTargetsInlineCell activity={activityFromCache} />
</ActivityTargetsContextProvider>
)}
{ActivityTargetsContextProvider &&
isDefined(activityFromCache) &&
isRightDrawerAnimationCompleted && (
<ActivityTargetsContextProvider>
<ActivityTargetsInlineCell
activity={activityFromCache}
maxWidth={340}
/>
</ActivityTargetsContextProvider>
)}
</StyledPropertyBox>
);
};
Original file line number Diff line number Diff line change
@@ -1,91 +1,47 @@
import { useMemo } from 'react';
import styled from '@emotion/styled';
import { Chip, ChipVariant } from 'twenty-ui';
import { v4 } from 'uuid';

import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
import { RecordChip } from '@/object-record/components/RecordChip';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import {
ExpandableList,
ExpandableListProps,
} from '@/ui/layout/expandable-list/ExpandableList';

const MAX_RECORD_CHIPS_DISPLAY = 2;

const StyledContainer = styled.div`
const StyledContainer = styled.div<{ maxWidth?: number }>`
display: flex;
flex-wrap: wrap;
gap: ${({ theme }) => theme.spacing(1)};
max-width: ${({ maxWidth }) => `${maxWidth}px` || 'none'};
`;

const StyledRelationsListContainer = styled(StyledContainer)`
padding: ${({ theme }) => theme.spacing(2)};
border-radius: ${({ theme }) => theme.spacing(1)};
background-color: ${({ theme }) => theme.background.secondary};
box-shadow: '0px 2px 4px ${({ theme }) =>
theme.boxShadow.light}, 2px 4px 16px ${({ theme }) =>
theme.boxShadow.strong}';
backdrop-filter: ${({ theme }) => theme.blur.strong};
`;

const showMoreRelationsHandler = (event?: React.MouseEvent<HTMLDivElement>) => {
event?.preventDefault();
event?.stopPropagation();
};

export const ActivityTargetChips = ({
activityTargetObjectRecords,
isHovered,
reference,
maxWidth,
}: {
activityTargetObjectRecords: ActivityTargetWithTargetRecord[];
}) => {
const dropdownId = useMemo(() => `multiple-relations-dropdown-${v4()}`, []);

maxWidth?: number;
} & ExpandableListProps) => {
return (
<StyledContainer>
{activityTargetObjectRecords
?.slice(0, MAX_RECORD_CHIPS_DISPLAY)
.map((activityTargetObjectRecord) => (
<RecordChip
key={activityTargetObjectRecord.targetObject.id}
record={activityTargetObjectRecord.targetObject}
objectNameSingular={
activityTargetObjectRecord.targetObjectMetadataItem.nameSingular
}
/>
))}

{activityTargetObjectRecords.length > MAX_RECORD_CHIPS_DISPLAY && (
<div onClick={showMoreRelationsHandler}>
<Dropdown
dropdownId={dropdownId}
dropdownHotkeyScope={{
scope: dropdownId,
}}
clickableComponent={
<Chip
label={`+${
activityTargetObjectRecords.length - MAX_RECORD_CHIPS_DISPLAY
}`}
variant={ChipVariant.Highlighted}
/>
}
dropdownOffset={{ x: 0, y: -20 }}
dropdownComponents={
<StyledRelationsListContainer>
{activityTargetObjectRecords.map(
(activityTargetObjectRecord) => (
<RecordChip
key={activityTargetObjectRecord.targetObject.id}
record={activityTargetObjectRecord.targetObject}
objectNameSingular={
activityTargetObjectRecord.targetObjectMetadataItem
.nameSingular
}
/>
),
)}
</StyledRelationsListContainer>
}
/>
</div>
)}
<StyledContainer maxWidth={maxWidth}>
<ExpandableList
isHovered={isHovered}
reference={reference}
forceDisplayHiddenCount
>
{activityTargetObjectRecords.map(
(activityTargetObjectRecord, index) => (
<RecordChip
key={index}
record={activityTargetObjectRecord.targetObject}
objectNameSingular={
activityTargetObjectRecord.targetObjectMetadataItem.nameSingular
}
/>
),
)}
</ExpandableList>
</StyledContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const StyledChip = styled.div`
padding: ${({ theme }) => theme.spacing(1)};
height: 20px;
box-sizing: border-box;
white-space: nowrap;
`;

type ParticipantChipVariant = 'default' | 'bold';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';

type ActivityTargetsInlineCellProps = {
activity: Activity;
showLabel?: boolean;
maxWidth?: number;
readonly?: boolean;
};

export const ActivityTargetsInlineCell = ({
activity,
showLabel = true,
maxWidth,
readonly,
}: ActivityTargetsInlineCellProps) => {
const { activityTargetObjectRecords } =
useActivityTargetObjectRecords(activity);
Expand All @@ -37,8 +43,9 @@ export const ActivityTargetsInlineCell = ({
customEditHotkeyScope={{
scope: ActivityEditorHotkeyScope.ActivityTargets,
}}
IconLabel={IconArrowUpRight}
showLabel={true}
IconLabel={showLabel ? IconArrowUpRight : undefined}
showLabel={showLabel}
readonly={readonly}
editModeContent={
<ActivityTargetInlineCellEditMode
activity={activity}
Expand All @@ -49,6 +56,7 @@ export const ActivityTargetsInlineCell = ({
displayModeContent={
<ActivityTargetChips
activityTargetObjectRecords={activityTargetObjectRecords}
maxWidth={maxWidth}
/>
}
isDisplayModeContentEmpty={activityTargetObjectRecords.length === 0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const NoteCard = ({
<StyledCardContent>{body}</StyledCardContent>
</StyledCardDetailsContainer>
<StyledFooter>
<ActivityTargetsInlineCell activity={note} />
<ActivityTargetsInlineCell activity={note} readonly />
{note.comments && note.comments.length > 0 && (
<StyledCommentIcon>
<IconComment size={theme.icon.size.md} />
Expand Down
Loading
Loading