Activity as standard object (#6219)

In this PR I layout the first steps to migrate Activity to a traditional
Standard objects

Since this is a big transition, I'd rather split it into several
deployments / PRs

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/012e2bbf-9d1b-4723-aaf6-269ef588b050">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: bosiraphael <71827178+bosiraphael@users.noreply.github.com>
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Faisal-imtiyaz123 <142205282+Faisal-imtiyaz123@users.noreply.github.com>
Co-authored-by: Prateek Jain <prateekj1171998@gmail.com>
This commit is contained in:
Félix Malfait
2024-07-31 15:36:11 +02:00
committed by GitHub
parent defcee2a02
commit 80c0fc7ff1
239 changed files with 18418 additions and 8671 deletions

View File

@ -0,0 +1,31 @@
import { RichTextEditor } from '@/activities/components/RichTextEditor';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import styled from '@emotion/styled';
const StyledShowPageActivityContainer = styled.div`
margin-top: ${({ theme }) => theme.spacing(2)};
width: 100%;
`;
export const ShowPageActivityContainer = ({
targetableObject,
}: {
targetableObject: Pick<
ActivityTargetableObject,
'targetObjectNameSingular' | 'id'
>;
}) => {
return (
<StyledShowPageActivityContainer>
<RichTextEditor
activityId={targetableObject.id}
fillTitleFromBody={false}
activityObjectNameSingular={
targetableObject.targetObjectNameSingular as
| CoreObjectNameSingular.Note
| CoreObjectNameSingular.Task
}
/>
</StyledShowPageActivityContainer>
);
};

View File

@ -2,7 +2,6 @@ import styled from '@emotion/styled';
import { IconCheckbox, IconNotes, IconPlus } from 'twenty-ui';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { ActivityType } from '@/activities/types/Activity';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
import { IconButton } from '@/ui/input/button/components/IconButton';
@ -11,6 +10,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { SHOW_PAGE_ADD_BUTTON_DROPDOWN_ID } from '@/ui/layout/show-page/constants/ShowPageAddButtonDropdownId';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { Dropdown } from '../../dropdown/components/Dropdown';
import { DropdownMenu } from '../../dropdown/components/DropdownMenu';
@ -24,17 +24,37 @@ export const ShowPageAddButton = ({
activityTargetObject: ActivityTargetableObject;
}) => {
const { closeDropdown, toggleDropdown } = useDropdown('add-show-page');
const openCreateActivity = useOpenCreateActivityDrawer();
const openNote = useOpenCreateActivityDrawer({
activityObjectNameSingular: CoreObjectNameSingular.Note,
});
const openTask = useOpenCreateActivityDrawer({
activityObjectNameSingular: CoreObjectNameSingular.Task,
});
const handleSelect = (type: ActivityType) => {
openCreateActivity({
type,
targetableObjects: [activityTargetObject],
});
const handleSelect = (objectNameSingular: CoreObjectNameSingular) => {
if (objectNameSingular === CoreObjectNameSingular.Note) {
openNote({
targetableObjects: [activityTargetObject],
});
}
if (objectNameSingular === CoreObjectNameSingular.Task) {
openTask({
targetableObjects: [activityTargetObject],
});
}
closeDropdown();
};
if (
activityTargetObject.targetObjectNameSingular ===
CoreObjectNameSingular.Task ||
activityTargetObject.targetObjectNameSingular ===
CoreObjectNameSingular.Note
) {
return;
}
return (
<StyledContainer>
<Dropdown
@ -53,13 +73,13 @@ export const ShowPageAddButton = ({
<DropdownMenu>
<DropdownMenuItemsContainer>
<MenuItem
onClick={() => handleSelect('Note')}
onClick={() => handleSelect(CoreObjectNameSingular.Note)}
accent="default"
LeftIcon={IconNotes}
text="Note"
/>
<MenuItem
onClick={() => handleSelect('Task')}
onClick={() => handleSelect(CoreObjectNameSingular.Task)}
accent="default"
LeftIcon={IconCheckbox}
text="Task"

View File

@ -3,7 +3,7 @@ import { useRecoilValue } from 'recoil';
import {
IconCalendarEvent,
IconCheckbox,
IconHome,
IconList,
IconMail,
IconNotes,
IconPaperclip,
@ -16,9 +16,9 @@ import { Attachments } from '@/activities/files/components/Attachments';
import { Notes } from '@/activities/notes/components/Notes';
import { ObjectTasks } from '@/activities/tasks/components/ObjectTasks';
import { TimelineActivities } from '@/activities/timelineActivities/components/TimelineActivities';
import { TimelineActivitiesQueryEffect } from '@/activities/timelineActivities/components/TimelineActivitiesQueryEffect';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer';
import { TabList } from '@/ui/layout/tab/components/TabList';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
@ -51,8 +51,9 @@ type ShowPageRightContainerProps = {
tasks?: boolean;
notes?: boolean;
emails?: boolean;
summary?: JSX.Element;
isRightDrawer?: boolean;
fieldsBox?: JSX.Element;
summaryCard?: JSX.Element;
isInRightDrawer?: boolean;
loading: boolean;
};
@ -63,10 +64,13 @@ export const ShowPageRightContainer = ({
notes,
emails,
loading,
summary,
isRightDrawer = false,
fieldsBox,
summaryCard,
isInRightDrawer = false,
}: ShowPageRightContainerProps) => {
const { activeTabIdState } = useTabList(TAB_LIST_COMPONENT_ID);
const { activeTabIdState } = useTabList(
`${TAB_LIST_COMPONENT_ID}-${isInRightDrawer}`,
);
const activeTabId = useRecoilValue(activeTabIdState);
const targetObjectNameSingular =
@ -80,24 +84,60 @@ export const ShowPageRightContainer = ({
const shouldDisplayCalendarTab = isCompanyOrPerson;
const shouldDisplayEmailsTab = emails && isCompanyOrPerson;
const isMobile = useIsMobile() || isRightDrawer;
const isMobile = useIsMobile() || isInRightDrawer;
const tabs = [
{
id: 'summary',
title: 'Summary',
Icon: IconHome,
id: 'richText',
title: 'Note',
Icon: IconNotes,
hide:
loading ||
(targetableObject.targetObjectNameSingular !==
CoreObjectNameSingular.Note &&
targetableObject.targetObjectNameSingular !==
CoreObjectNameSingular.Task),
},
{
id: 'fields',
title: 'Fields',
Icon: IconList,
hide: !isMobile,
},
{
id: 'timeline',
title: 'Timeline',
Icon: IconTimelineEvent,
hide: !timeline || isRightDrawer,
hide: !timeline || isInRightDrawer,
},
{
id: 'tasks',
title: 'Tasks',
Icon: IconCheckbox,
hide:
!tasks ||
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Note ||
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Task,
},
{
id: 'notes',
title: 'Notes',
Icon: IconNotes,
hide:
!notes ||
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Note ||
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Task,
},
{
id: 'files',
title: 'Files',
Icon: IconPaperclip,
hide: !notes,
},
{ id: 'tasks', title: 'Tasks', Icon: IconCheckbox, hide: !tasks },
{ id: 'notes', title: 'Notes', Icon: IconNotes, hide: !notes },
{ id: 'files', title: 'Files', Icon: IconPaperclip, hide: !notes },
{
id: 'emails',
title: 'Emails',
@ -117,14 +157,23 @@ export const ShowPageRightContainer = ({
case 'timeline':
return (
<>
<TimelineActivitiesQueryEffect
<TimelineActivities
targetableObject={targetableObject}
isInRightDrawer={isInRightDrawer}
/>
<TimelineActivities targetableObject={targetableObject} />
</>
);
case 'summary':
return summary;
case 'richText':
return (
(targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Note ||
targetableObject.targetObjectNameSingular ===
CoreObjectNameSingular.Task) && (
<ShowPageActivityContainer targetableObject={targetableObject} />
)
);
case 'fields':
return fieldsBox;
case 'tasks':
return <ObjectTasks targetableObject={targetableObject} />;
case 'notes':
@ -142,10 +191,11 @@ export const ShowPageRightContainer = ({
return (
<StyledShowPageRightContainer isMobile={isMobile}>
{summaryCard}
<StyledTabListContainer>
<TabList
loading={loading}
tabListId={TAB_LIST_COMPONENT_ID}
tabListId={`${TAB_LIST_COMPONENT_ID}-${isInRightDrawer}`}
tabs={tabs}
/>
</StyledTabListContainer>