Time line activity wrong type (#11673)

# Introduction
Closes https://github.com/twentyhq/core-team-issues/issues/874

`TimeLineActivity` fields `` and `` were typed as required whereas in
reality are nullable, resulting in the related sentry error.
Refactored the type then the related components in order to handle
nullable use case
This commit is contained in:
Paul Rastoin
2025-04-22 17:17:08 +02:00
committed by GitHub
parent efab98a8f8
commit de1489aabb
6 changed files with 49 additions and 18 deletions

View File

@ -3,11 +3,14 @@ import { useRecoilValue } from 'recoil';
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
export const useLinkedObjectObjectMetadataItem = (id: string) => {
export const useLinkedObjectObjectMetadataItem = (id: string | null) => {
const objectMetadataItems: ObjectMetadataItem[] = useRecoilValue(
objectMetadataItemsState,
);
if (id === null) {
return null;
}
return (
objectMetadataItems.find(
(objectMetadataItem) => objectMetadataItem.id === id,

View File

@ -6,6 +6,7 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadata
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields';
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { isDefined } from 'twenty-shared/utils';
// do we need to test this?
export const useTimelineActivities = (
@ -41,7 +42,8 @@ export const useTimelineActivities = (
const activityIds = timelineActivities
.filter((timelineActivity) => timelineActivity.name.match(/note|task/i))
.map((timelineActivity) => timelineActivity.linkedRecordId);
.map((timelineActivity) => timelineActivity.linkedRecordId)
.filter(isDefined);
const { loading: loadingLinkedObjectsTitle } =
useLinkedObjectsTitle(activityIds);

View File

@ -5,12 +5,13 @@ import {
StyledEventRowItemAction,
StyledEventRowItemColumn,
} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent';
import { isTimelineActivityWithLinkedRecord } from '@/activities/timeline-activities/types/TimelineActivity';
import { useOpenRecordInCommandMenu } from '@/command-menu/hooks/useOpenRecordInCommandMenu';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
import { isNonEmptyString } from '@sniptt/guards';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
type EventRowActivityProps = EventRowDynamicComponentProps;
@ -67,7 +68,7 @@ export const EventRowActivity = ({
const eventObject = eventLinkedObject.replace('linked-', '');
if (!event.linkedRecordId) {
if (!isTimelineActivityWithLinkedRecord(event)) {
throw new Error('Could not find linked record id for event');
}
@ -81,11 +82,18 @@ export const EventRowActivity = ({
const activityInStore = getActivityFromCache(event.linkedRecordId);
const activityTitle = isNonEmptyString(activityInStore?.title)
? activityInStore?.title
: isNonEmptyString(event.linkedRecordCachedName)
? event.linkedRecordCachedName
: 'Untitled';
const computeActivityTitle = () => {
if (isNonEmptyString(activityInStore?.title)) {
return activityInStore?.title;
}
if (isNonEmptyString(event.linkedRecordCachedName)) {
return event.linkedRecordCachedName;
}
return 'Untitled';
};
const activityTitle = computeActivityTitle();
const { openRecordInCommandMenu } = useOpenRecordInCommandMenu();

View File

@ -9,6 +9,7 @@ import {
StyledEventRowItemAction,
StyledEventRowItemColumn,
} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent';
import { isTimelineActivityWithLinkedRecord } from '@/activities/timeline-activities/types/TimelineActivity';
type EventRowCalendarEventProps = EventRowDynamicComponentProps;
@ -45,9 +46,11 @@ export const EventRowCalendarEvent = ({
</StyledEventRowItemAction>
<EventCardToggleButton isOpen={isOpen} setIsOpen={setIsOpen} />
</StyledRowContainer>
<EventCard isOpen={isOpen}>
<EventCardCalendarEvent calendarEventId={event.linkedRecordId} />
</EventCard>
{isTimelineActivityWithLinkedRecord(event) && (
<EventCard isOpen={isOpen}>
<EventCardCalendarEvent calendarEventId={event.linkedRecordId} />
</EventCard>
)}
</StyledEventRowCalendarEventContainer>
);
};

View File

@ -9,6 +9,7 @@ import {
StyledEventRowItemColumn,
} from '@/activities/timeline-activities/rows/components/EventRowDynamicComponent';
import { EventCardMessage } from '@/activities/timeline-activities/rows/message/components/EventCardMessage';
import { isTimelineActivityWithLinkedRecord } from '@/activities/timeline-activities/types/TimelineActivity';
type EventRowMessageProps = EventRowDynamicComponentProps;
@ -49,10 +50,12 @@ export const EventRowMessage = ({
<EventCardToggleButton isOpen={isOpen} setIsOpen={setIsOpen} />
</StyledRowContainer>
<EventCard isOpen={isOpen}>
<EventCardMessage
messageId={event.linkedRecordId}
authorFullName={authorFullName}
/>
{isTimelineActivityWithLinkedRecord(event) && (
<EventCardMessage
messageId={event.linkedRecordId}
authorFullName={authorFullName}
/>
)}
</EventCard>
</StyledEventRowMessageContainer>
);

View File

@ -1,3 +1,4 @@
import { isDefined } from 'twenty-shared/utils';
import { WorkspaceMember } from '~/generated/graphql';
export type TimelineActivity = {
@ -10,7 +11,18 @@ export type TimelineActivity = {
properties: any;
name: string;
linkedRecordCachedName: string;
linkedRecordId: string;
linkedObjectMetadataId: string;
linkedRecordId: string | null;
linkedObjectMetadataId: string | null;
__typename: 'TimelineActivity';
} & Record<string, any>;
export type TimelineActivityWithRecord = TimelineActivity & {
linkedRecordId: string;
linkedObjectMetadataId: string;
};
export const isTimelineActivityWithLinkedRecord = (
timelineActivity: TimelineActivity,
): timelineActivity is TimelineActivityWithRecord =>
isDefined(timelineActivity.linkedObjectMetadataId) &&
isDefined(timelineActivity.linkedRecordId);