Feat/activity optimistic activities (#4009)

* Fix naming

* Fixed cache.evict bug for relation target deletion

* Fixed cascade delete activity targets

* Working version

* Fix

* fix

* WIP

* Fixed optimistic effect target inline cell

* Removed openCreateActivityDrawer v1

* Ok for timeline

* Removed console.log

* Fix update record optimistic effect

* Refactored activity queries into useActivities for everything

* Fixed bugs

* Cleaned

* Fix lint

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Lucas Bordeau
2024-02-20 14:20:45 +01:00
committed by GitHub
parent 6fb0099eb3
commit 36a6558289
68 changed files with 1435 additions and 630 deletions

View File

@ -1,7 +1,11 @@
import { useEffect } from 'react';
import styled from '@emotion/styled';
import { useSetRecoilState } from 'recoil';
import { useActivities } from '@/activities/hooks/useActivities';
import { TimelineCreateButtonGroup } from '@/activities/timeline/components/TimelineCreateButtonGroup';
import { useTimelineActivities } from '@/activities/timeline/hooks/useTimelineActivities';
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY';
import { timelineTargetableObjectState } from '@/activities/timeline/states/timelineTargetableObjectState';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
import {
@ -11,6 +15,7 @@ import {
AnimatedPlaceholderEmptyTitle,
} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { isDefined } from '~/utils/isDefined';
import { TimelineItemsContainer } from './TimelineItemsContainer';
@ -31,11 +36,22 @@ export const Timeline = ({
}: {
targetableObject: ActivityTargetableObject;
}) => {
const { activities, initialized } = useTimelineActivities({
targetableObject,
const { activities, initialized, noActivities } = useActivities({
targetableObjects: [targetableObject],
activitiesFilters: {},
activitiesOrderByVariables: FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
skip: !isDefined(targetableObject),
});
const showEmptyState = initialized && activities.length === 0;
const setTimelineTargetableObject = useSetRecoilState(
timelineTargetableObjectState,
);
useEffect(() => {
setTimelineTargetableObject(targetableObject);
}, [targetableObject, setTimelineTargetableObject]);
const showEmptyState = noActivities;
const showLoadingState = !initialized;

View File

@ -1,13 +1,14 @@
import { Tooltip } from 'react-tooltip';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { useOpenActivityRightDrawer } from '@/activities/hooks/useOpenActivityRightDrawer';
import { Activity } from '@/activities/types/Activity';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { IconCheckbox, IconNotes } from '@/ui/display/icon';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { Avatar } from '@/users/components/Avatar';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import {
beautifyExactDateTime,
beautifyPastDateRelativeToNow,
@ -135,19 +136,7 @@ const StyledTimelineItemContainer = styled.div<{ isGap?: boolean }>`
`;
type TimelineActivityProps = {
activity: Pick<
Activity,
| 'id'
| 'title'
| 'body'
| 'createdAt'
| 'completedAt'
| 'type'
| 'comments'
| 'dueAt'
> & { author?: Pick<WorkspaceMember, 'name' | 'avatarUrl'> } & {
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
};
activity: Activity;
isLastActivity?: boolean;
};
@ -160,6 +149,8 @@ export const TimelineActivity = ({
const openActivityRightDrawer = useOpenActivityRightDrawer();
const theme = useTheme();
const activityFromStore = useRecoilValue(recordStoreFamilyState(activity.id));
return (
<>
<StyledTimelineItemContainer>
@ -191,11 +182,13 @@ export const TimelineActivity = ({
</StyledIconContainer>
{(activity.type === 'Note' || activity.type === 'Task') && (
<StyledActivityTitle
onClick={() => openActivityRightDrawer(activity.id)}
onClick={() => openActivityRightDrawer(activity)}
>
<StyledActivityLink title={activity.title ?? '(No Title)'}>
{activity.title ?? '(No Title)'}
<StyledActivityLink
title={activityFromStore?.title ?? '(No Title)'}
>
{activityFromStore?.title ?? '(No Title)'}
</StyledActivityLink>
</StyledActivityTitle>

View File

@ -1,7 +1,7 @@
import { useSetRecoilState } from 'recoil';
import { Button, ButtonGroup } from 'tsup.ui.index';
import { useOpenCreateActivityDrawerV2 } from '@/activities/hooks/useOpenCreateActivityDrawerV2';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import {
IconCheckbox,
@ -19,7 +19,7 @@ export const TimelineCreateButtonGroup = ({
const { getActiveTabIdState } = useTabList(TAB_LIST_COMPONENT_ID);
const setActiveTabId = useSetRecoilState(getActiveTabIdState());
const openCreateActivity = useOpenCreateActivityDrawerV2();
const openCreateActivity = useOpenCreateActivityDrawer();
return (
<ButtonGroup variant={'secondary'}>
@ -30,7 +30,6 @@ export const TimelineCreateButtonGroup = ({
openCreateActivity({
type: 'Note',
targetableObjects: [targetableObject],
timelineTargetableObject: targetableObject,
})
}
/>
@ -41,7 +40,6 @@ export const TimelineCreateButtonGroup = ({
openCreateActivity({
type: 'Task',
targetableObjects: [targetableObject],
timelineTargetableObject: targetableObject,
})
}
/>