Skip to content

Commit

Permalink
4900 multi select field front implement expanded cells (twentyhq#5151)
Browse files Browse the repository at this point in the history
  • Loading branch information
martmull authored and i-am-chitti committed May 4, 2024
1 parent 089164b commit 726d5d1
Show file tree
Hide file tree
Showing 51 changed files with 687 additions and 405 deletions.
6 changes: 3 additions & 3 deletions packages/twenty-front/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { CommandMenuEffect } from '~/effect-components/CommandMenuEffect';
import { GotoHotkeysEffect } from '~/effect-components/GotoHotkeysEffect';
import { Authorize } from '~/pages/auth/Authorize';
import { ChooseYourPlan } from '~/pages/auth/ChooseYourPlan.tsx';
import { ChooseYourPlan } from '~/pages/auth/ChooseYourPlan';
import { CreateProfile } from '~/pages/auth/CreateProfile';
import { CreateWorkspace } from '~/pages/auth/CreateWorkspace';
import { PasswordReset } from '~/pages/auth/PasswordReset';
import { PaymentSuccess } from '~/pages/auth/PaymentSuccess.tsx';
import { PaymentSuccess } from '~/pages/auth/PaymentSuccess';
import { SignInUp } from '~/pages/auth/SignInUp';
import { DefaultHomePage } from '~/pages/DefaultHomePage';
import { ImpersonateEffect } from '~/pages/impersonate/ImpersonateEffect';
Expand Down Expand Up @@ -46,7 +46,7 @@ import { SettingsIntegrationNewDatabaseConnection } from '~/pages/settings/integ
import { SettingsIntegrations } from '~/pages/settings/integrations/SettingsIntegrations';
import { SettingsIntegrationShowDatabaseConnection } from '~/pages/settings/integrations/SettingsIntegrationShowDatabaseConnection';
import { SettingsAppearance } from '~/pages/settings/SettingsAppearance';
import { SettingsBilling } from '~/pages/settings/SettingsBilling.tsx';
import { SettingsBilling } from '~/pages/settings/SettingsBilling';
import { SettingsProfile } from '~/pages/settings/SettingsProfile';
import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace';
import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers';
Expand Down
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/components/ExpandableList';
import { isRightDrawerAnimationCompletedState } from '@/ui/layout/right-drawer/states/isRightDrawerAnimationCompleted';

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';
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/components/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

0 comments on commit 726d5d1

Please sign in to comment.