From 00e418a039ce2fe213f2600f84fe9d7eb142ff6b Mon Sep 17 00:00:00 2001 From: martmull Date: Tue, 28 Jul 2026 23:26:59 +0200 Subject: [PATCH] Show call recorders as calendar event participants (#23380) Closes twentyhq/core-team-issues#2729 Call recordings attached to a calendar event are now displayed next to the human participants, in the timeline event card (`EventCardCalendarEvent`). They are rendered as the source app's `AppChip`, rounded so it sits in the participant avatar group, with the recording status in tooltip https://github.com/user-attachments/assets/e0c393c8-fd65-4468-8c4f-503dd22c13d5 ## Before No call recorder chip displayed TODO: add this in the calendar views (`CalendarEventRow`) --- .../twenty-front/src/generated/graphql.ts | 33 +++++++-- .../CalendarEventCallRecorderAvatar.tsx | 74 +++++++++++++++++++ .../CalendarEventParticipantsAvatarGroup.tsx | 47 +++++++----- .../calendar/components/CalendarEventRow.tsx | 6 +- ...elineCalendarEventCallRecordingFragment.ts | 9 +++ .../timelineCalendarEventFragment.ts | 5 ++ .../__tests__/useCalendarEvents.test.tsx | 4 + .../calendar/types/CalendarEvent.ts | 2 + .../types/CalendarEventCallRecording.ts | 7 ++ .../components/EventCardCalendarEvent.tsx | 11 ++- .../applications/components/AppChip.tsx | 7 +- ...ettingsAccountsCalendarChannelsGeneral.tsx | 1 + .../mock-data/timeline-calendar-events.ts | 18 +++++ ...eline-calendar-event-call-recording.dto.ts | 21 ++++++ .../dtos/timeline-calendar-event.dto.ts | 4 + .../timeline-calendar-event.service.spec.ts | 9 +++ .../timeline-calendar-event.service.ts | 49 ++++++++++++ .../data-display/Avatar/Avatar.module.scss | 20 +++++ .../Avatar/Avatar.module.scss.d.ts | 1 + .../src/data-display/Avatar/Avatar.tsx | 9 ++- 20 files changed, 308 insertions(+), 29 deletions(-) create mode 100644 packages/twenty-front/src/modules/activities/calendar/components/CalendarEventCallRecorderAvatar.tsx create mode 100644 packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventCallRecordingFragment.ts create mode 100644 packages/twenty-front/src/modules/activities/calendar/types/CalendarEventCallRecording.ts create mode 100644 packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-call-recording.dto.ts diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 6510a6ca70..ed12eda83f 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -23,6 +23,16 @@ export enum CalendarChannelVisibility { SHARE_EVERYTHING = 'SHARE_EVERYTHING' } +/** Recording lifecycle status */ +export enum CallRecordingStatus { + COMPLETED = 'COMPLETED', + FAILED = 'FAILED', + JOINING = 'JOINING', + PROCESSING = 'PROCESSING', + RECORDING = 'RECORDING', + SCHEDULED = 'SCHEDULED' +} + export type ComputeStepOutputSchemaInput = { /** Step JSON format */ step: Scalars['JSON']['input']; @@ -514,6 +524,7 @@ export type TestHttpRequestInput = { export type TimelineCalendarEvent = { __typename?: 'TimelineCalendarEvent'; + callRecordings: Array; conferenceLink: LinksMetadata; conferenceSolution: Scalars['String']['output']; description: Scalars['String']['output']; @@ -528,6 +539,13 @@ export type TimelineCalendarEvent = { visibility: CalendarChannelVisibility; }; +export type TimelineCalendarEventCallRecording = { + __typename?: 'TimelineCalendarEventCallRecording'; + applicationId?: Maybe; + id: Scalars['UUID']['output']; + status: CallRecordingStatus; +}; + export type TimelineCalendarEventParticipant = { __typename?: 'TimelineCalendarEventParticipant'; avatarUrl: Scalars['String']['output']; @@ -709,11 +727,13 @@ export type WorkflowVersionTrigger = { trigger?: Maybe; }; -export type TimelineCalendarEventFragmentFragment = { __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }; +export type TimelineCalendarEventCallRecordingFragmentFragment = { __typename?: 'TimelineCalendarEventCallRecording', id: any, status: CallRecordingStatus, applicationId?: any | null }; + +export type TimelineCalendarEventFragmentFragment = { __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }>, callRecordings: Array<{ __typename?: 'TimelineCalendarEventCallRecording', id: any, status: CallRecordingStatus, applicationId?: any | null }> }; export type TimelineCalendarEventParticipantFragmentFragment = { __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }; -export type TimelineCalendarEventsWithTotalFragmentFragment = { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, relatedPersonIds: Array, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> }; +export type TimelineCalendarEventsWithTotalFragmentFragment = { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, relatedPersonIds: Array, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }>, callRecordings: Array<{ __typename?: 'TimelineCalendarEventCallRecording', id: any, status: CallRecordingStatus, applicationId?: any | null }> }> }; export type GetTimelineCalendarEventsFromObjectRecordQueryVariables = Exact<{ objectNameSingular: Scalars['String']['input']; @@ -723,7 +743,7 @@ export type GetTimelineCalendarEventsFromObjectRecordQueryVariables = Exact<{ }>; -export type GetTimelineCalendarEventsFromObjectRecordQuery = { __typename?: 'Query', getTimelineCalendarEventsFromObjectRecord: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, relatedPersonIds: Array, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } }; +export type GetTimelineCalendarEventsFromObjectRecordQuery = { __typename?: 'Query', getTimelineCalendarEventsFromObjectRecord: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, relatedPersonIds: Array, timelineCalendarEvents: Array<{ __typename?: 'TimelineCalendarEvent', id: any, title: string, description: string, location: string, startsAt: string, endsAt: string, isFullDay: boolean, visibility: CalendarChannelVisibility, participants: Array<{ __typename?: 'TimelineCalendarEventParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }>, callRecordings: Array<{ __typename?: 'TimelineCalendarEventCallRecording', id: any, status: CallRecordingStatus, applicationId?: any | null }> }> } }; export type ParticipantFragmentFragment = { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }; @@ -896,13 +916,14 @@ export type UpdateWorkflowVersionPositionsMutationVariables = Exact<{ export type UpdateWorkflowVersionPositionsMutation = { __typename?: 'Mutation', updateWorkflowVersionPositions: boolean }; export const TimelineCalendarEventParticipantFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}}]} as unknown as DocumentNode; -export const TimelineCalendarEventFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}}]} as unknown as DocumentNode; -export const TimelineCalendarEventsWithTotalFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfCalendarEvents"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}}]}}]} as unknown as DocumentNode; +export const TimelineCalendarEventCallRecordingFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventCallRecording"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}}]}}]} as unknown as DocumentNode; +export const TimelineCalendarEventFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"callRecordings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventCallRecording"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}}]}}]} as unknown as DocumentNode; +export const TimelineCalendarEventsWithTotalFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfCalendarEvents"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventCallRecording"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"callRecordings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"}}]}}]}}]} as unknown as DocumentNode; export const ParticipantFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}}]} as unknown as DocumentNode; export const TimelineThreadFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineThreadFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThread"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"read"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"firstParticipant"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastTwoParticipants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageReceivedAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageBody"}},{"kind":"Field","name":{"kind":"Name","value":"subject"}},{"kind":"Field","name":{"kind":"Name","value":"numberOfMessagesInThread"}},{"kind":"Field","name":{"kind":"Name","value":"participantCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageIsDraft"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}}]} as unknown as DocumentNode; export const TimelineThreadsWithTotalFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineThreadsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfThreads"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineThreadFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThread"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"read"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"firstParticipant"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastTwoParticipants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageReceivedAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageBody"}},{"kind":"Field","name":{"kind":"Name","value":"subject"}},{"kind":"Field","name":{"kind":"Name","value":"numberOfMessagesInThread"}},{"kind":"Field","name":{"kind":"Name","value":"participantCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageIsDraft"}}]}}]} as unknown as DocumentNode; export const WorkflowDiffFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"WorkflowDiffFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"WorkflowVersionStepChanges"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"triggerDiff"}},{"kind":"Field","name":{"kind":"Name","value":"stepsDiff"}}]}}]} as unknown as DocumentNode; -export const GetTimelineCalendarEventsFromObjectRecordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineCalendarEventsFromObjectRecord"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getTimelineCalendarEventsFromObjectRecord"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"objectNameSingular"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}}},{"kind":"Argument","name":{"kind":"Name","value":"recordId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfCalendarEvents"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode; +export const GetTimelineCalendarEventsFromObjectRecordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineCalendarEventsFromObjectRecord"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getTimelineCalendarEventsFromObjectRecord"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"objectNameSingular"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}}},{"kind":"Argument","name":{"kind":"Name","value":"recordId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventCallRecording"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEvent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"location"}},{"kind":"Field","name":{"kind":"Name","value":"startsAt"}},{"kind":"Field","name":{"kind":"Name","value":"endsAt"}},{"kind":"Field","name":{"kind":"Name","value":"isFullDay"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"participants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"callRecordings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventCallRecordingFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineCalendarEventsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfCalendarEvents"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode; export const GetTimelineThreadsFromObjectRecordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineThreadsFromObjectRecord"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"page"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getTimelineThreadsFromObjectRecord"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"objectNameSingular"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectNameSingular"}}},{"kind":"Argument","name":{"kind":"Name","value":"recordId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"recordId"}}},{"kind":"Argument","name":{"kind":"Name","value":"page"},"value":{"kind":"Variable","name":{"kind":"Name","value":"page"}}},{"kind":"Argument","name":{"kind":"Name","value":"pageSize"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pageSize"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadsWithTotalFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ParticipantFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadParticipant"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"personId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceMemberId"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineThreadFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThread"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"read"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"firstParticipant"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastTwoParticipants"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ParticipantFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageReceivedAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageBody"}},{"kind":"Field","name":{"kind":"Name","value":"subject"}},{"kind":"Field","name":{"kind":"Name","value":"numberOfMessagesInThread"}},{"kind":"Field","name":{"kind":"Name","value":"participantCount"}},{"kind":"Field","name":{"kind":"Name","value":"lastMessageIsDraft"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"TimelineThreadsWithTotalFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"TimelineThreadsWithTotal"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalNumberOfThreads"}},{"kind":"Field","name":{"kind":"Name","value":"relatedPersonIds"}},{"kind":"Field","name":{"kind":"Name","value":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}}]} as unknown as DocumentNode; export const SearchDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Search"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchInput"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"after"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"excludedObjectNameSingulars"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"includedObjectNameSingulars"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ObjectRecordFilterInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"search"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchInput"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchInput"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"after"},"value":{"kind":"Variable","name":{"kind":"Name","value":"after"}}},{"kind":"Argument","name":{"kind":"Name","value":"excludedObjectNameSingulars"},"value":{"kind":"Variable","name":{"kind":"Name","value":"excludedObjectNameSingulars"}}},{"kind":"Argument","name":{"kind":"Name","value":"includedObjectNameSingulars"},"value":{"kind":"Variable","name":{"kind":"Name","value":"includedObjectNameSingulars"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"recordId"}},{"kind":"Field","name":{"kind":"Name","value":"objectNameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"objectLabelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"imageUrl"}},{"kind":"Field","name":{"kind":"Name","value":"tsRankCD"}},{"kind":"Field","name":{"kind":"Name","value":"tsRank"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}},{"kind":"Field","name":{"kind":"Name","value":"endCursor"}}]}}]}}]}}]} as unknown as DocumentNode; export const ActivateWorkflowVersionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ActivateWorkflowVersion"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workflowVersionId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activateWorkflowVersion"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workflowVersionId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workflowVersionId"}}}]}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventCallRecorderAvatar.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventCallRecorderAvatar.tsx new file mode 100644 index 0000000000..5390b108dd --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventCallRecorderAvatar.tsx @@ -0,0 +1,74 @@ +import { AppChip } from '@/applications/components/AppChip'; +import { styled } from '@linaria/react'; +import { t } from '@lingui/core/macro'; +import { useId } from 'react'; +import { createPortal } from 'react-dom'; +import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/surfaces'; +import { CallRecordingStatus } from '~/generated/graphql'; + +const IN_PROGRESS_CALL_RECORDING_STATUSES: CallRecordingStatus[] = [ + CallRecordingStatus.JOINING, + CallRecordingStatus.RECORDING, + CallRecordingStatus.PROCESSING, +]; + +const getCallRecordingStatusLabel = (status: CallRecordingStatus) => { + switch (status) { + case CallRecordingStatus.SCHEDULED: + return t`Scheduled`; + case CallRecordingStatus.JOINING: + return t`Joining`; + case CallRecordingStatus.RECORDING: + return t`Recording`; + case CallRecordingStatus.PROCESSING: + return t`Processing`; + case CallRecordingStatus.COMPLETED: + return t`Completed`; + case CallRecordingStatus.FAILED: + return t`Failed`; + } +}; + +const StyledContainer = styled.div<{ isDisabled: boolean }>` + display: flex; + filter: ${({ isDisabled }) => (isDisabled ? 'grayscale(1)' : 'none')}; +`; + +type CalendarEventCallRecorderAvatarProps = { + applicationId?: string | null; + status: CallRecordingStatus; +}; + +export const CalendarEventCallRecorderAvatar = ({ + applicationId, + status, +}: CalendarEventCallRecorderAvatarProps) => { + const instanceId = useId(); + const hasFailed = status === CallRecordingStatus.FAILED; + const tooltipAnchorId = `call-recorder-${instanceId.replace(/[^a-zA-Z0-9-_]/g, '-')}`; + + return ( + <> + + + + {createPortal( + , + document.body, + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsAvatarGroup.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsAvatarGroup.tsx index d760419034..88ad72a8a1 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsAvatarGroup.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventParticipantsAvatarGroup.tsx @@ -1,3 +1,5 @@ +import { CalendarEventCallRecorderAvatar } from '@/activities/calendar/components/CalendarEventCallRecorderAvatar'; +import { type CalendarEventCallRecording } from '@/activities/calendar/types/CalendarEventCallRecording'; import { type CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant'; import { isTimelineCalendarEventParticipant } from '@/activities/calendar/types/guards/IsTimelineCalendarEventParticipant'; import { isDefined } from 'twenty-shared/utils'; @@ -7,10 +9,12 @@ import { getAbsoluteImageUrl } from '~/utils/image/getAbsoluteImageUrl'; type CalendarEventParticipantsAvatarGroupProps = { participants: CalendarEventParticipant[] | TimelineCalendarEventParticipant[]; + callRecordings?: CalendarEventCallRecording[]; }; export const CalendarEventParticipantsAvatarGroup = ({ participants, + callRecordings = [], }: CalendarEventParticipantsAvatarGroupProps) => { const timelineParticipants: TimelineCalendarEventParticipant[] = participants.map((participant) => { @@ -47,23 +51,32 @@ export const CalendarEventParticipantsAvatarGroup = ({ return ( ( - - ))} + avatars={[ + ...callRecordings.map((callRecording) => ( + + )), + ...timelineParticipants.map((participant) => ( + + )), + ]} /> ); }; diff --git a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx index aa6dcb7bf4..cf30792759 100644 --- a/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/components/CalendarEventRow.tsx @@ -125,9 +125,11 @@ export const CalendarEventRow = ({ )} - {!!calendarEvent.participants?.length && ( + {(!!calendarEvent.participants?.length || + !!calendarEvent.callRecordings?.length) && ( )} diff --git a/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventCallRecordingFragment.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventCallRecordingFragment.ts new file mode 100644 index 0000000000..326bd11938 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventCallRecordingFragment.ts @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client'; + +export const timelineCalendarEventCallRecordingFragment = gql` + fragment TimelineCalendarEventCallRecordingFragment on TimelineCalendarEventCallRecording { + id + status + applicationId + } +`; diff --git a/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts index eb152294cc..635d954e0c 100644 --- a/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts +++ b/packages/twenty-front/src/modules/activities/calendar/graphql/queries/fragments/timelineCalendarEventFragment.ts @@ -1,3 +1,4 @@ +import { timelineCalendarEventCallRecordingFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventCallRecordingFragment'; import { timelineCalendarEventParticipantFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventParticipantFragment'; import { gql } from '@apollo/client'; @@ -14,6 +15,10 @@ export const timelineCalendarEventFragment = gql` participants { ...TimelineCalendarEventParticipantFragment } + callRecordings { + ...TimelineCalendarEventCallRecordingFragment + } } ${timelineCalendarEventParticipantFragment} + ${timelineCalendarEventCallRecordingFragment} `; diff --git a/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx index 36b801236f..7d3b639938 100644 --- a/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx +++ b/packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx @@ -23,6 +23,7 @@ const calendarEvents: TimelineCalendarEvent[] = [ isCanceled: false, location: 'Location', participants: [], + callRecordings: [], title: 'Title', __typename: 'TimelineCalendarEvent', }, @@ -42,6 +43,7 @@ const calendarEvents: TimelineCalendarEvent[] = [ isCanceled: false, location: 'Location', participants: [], + callRecordings: [], title: 'Title', __typename: 'TimelineCalendarEvent', }, @@ -61,6 +63,7 @@ const calendarEvents: TimelineCalendarEvent[] = [ isCanceled: false, location: 'Location', participants: [], + callRecordings: [], title: 'Title', __typename: 'TimelineCalendarEvent', }, @@ -80,6 +83,7 @@ const calendarEvents: TimelineCalendarEvent[] = [ isCanceled: false, location: 'Location', participants: [], + callRecordings: [], title: 'Title', __typename: 'TimelineCalendarEvent', }, diff --git a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts index 5fd82560ee..59f5bd489d 100644 --- a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts +++ b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEvent.ts @@ -1,3 +1,4 @@ +import { type CalendarEventCallRecording } from '@/activities/calendar/types/CalendarEventCallRecording'; import { type CalendarEventParticipant } from '@/activities/calendar/types/CalendarEventParticipant'; import { type CalendarChannelVisibility } from '~/generated/graphql'; @@ -18,5 +19,6 @@ export type CalendarEvent = { title?: string; visibility: CalendarChannelVisibility; calendarEventParticipants?: CalendarEventParticipant[]; + callRecordings?: CalendarEventCallRecording[]; __typename: 'CalendarEvent'; }; diff --git a/packages/twenty-front/src/modules/activities/calendar/types/CalendarEventCallRecording.ts b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEventCallRecording.ts new file mode 100644 index 0000000000..38a2b3ca83 --- /dev/null +++ b/packages/twenty-front/src/modules/activities/calendar/types/CalendarEventCallRecording.ts @@ -0,0 +1,7 @@ +import { type CallRecordingStatus } from '~/generated/graphql'; + +export type CalendarEventCallRecording = { + id: string; + status: CallRecordingStatus; + applicationId?: string | null; +}; diff --git a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx index bc14ea8f7b..dc9a17a2de 100644 --- a/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx +++ b/packages/twenty-front/src/modules/activities/timeline-activities/rows/calendar/components/EventCardCalendarEvent.tsx @@ -116,6 +116,11 @@ export const EventCardCalendarEvent = ({ handle: true, displayName: true, }, + callRecordings: { + id: true, + status: true, + applicationId: true, + }, }, }); @@ -195,9 +200,11 @@ export const EventCardCalendarEvent = ({ {calendarEvent.title} )} - {!!calendarEvent.calendarEventParticipants?.length && ( + {(!!calendarEvent.calendarEventParticipants?.length || + !!calendarEvent.callRecordings?.length) && ( )} diff --git a/packages/twenty-front/src/modules/applications/components/AppChip.tsx b/packages/twenty-front/src/modules/applications/components/AppChip.tsx index ca68832f94..7143cab7e6 100644 --- a/packages/twenty-front/src/modules/applications/components/AppChip.tsx +++ b/packages/twenty-front/src/modules/applications/components/AppChip.tsx @@ -17,6 +17,8 @@ type AppChipProps = { }; className?: string; chipOnly?: boolean; + rounded?: boolean; + pulsing?: boolean; }; const StyledContainer = styled.div` @@ -38,6 +40,8 @@ export const AppChip = ({ fallbackApplicationData, className, chipOnly = false, + rounded = false, + pulsing = false, }: AppChipProps) => { const { applicationChipData } = useApplicationChipData({ applicationId, @@ -47,7 +51,7 @@ export const AppChip = ({ return ( {!chipOnly && ( diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx index 90ab57ea81..ff44fb8529 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarChannelsGeneral.tsx @@ -49,6 +49,7 @@ export const SettingsAccountsCalendarChannelsGeneral = () => { workspaceMemberId: currentWorkspaceMember?.id || '', }, ], + callRecordings: [], endsAt: exampleEndDate.toISOString(), isFullDay: false, startsAt: exampleStartDate.toISOString(), diff --git a/packages/twenty-front/src/testing/mock-data/timeline-calendar-events.ts b/packages/twenty-front/src/testing/mock-data/timeline-calendar-events.ts index 78a389b4e0..a957c1f48b 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-calendar-events.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-calendar-events.ts @@ -1,5 +1,6 @@ import { CalendarChannelVisibility, + CallRecordingStatus, type TimelineCalendarEvent, } from '~/generated/graphql'; @@ -42,6 +43,14 @@ export const mockedTimelineCalendarEvents: TimelineCalendarEvent[] = [ handle: 'jane@apple.dev', }, ], + callRecordings: [ + { + __typename: 'TimelineCalendarEventCallRecording', + id: '20202020-9f2c-4a1a-9c5d-2f6a1b3c4d5e', + status: CallRecordingStatus.COMPLETED, + applicationId: null, + }, + ], }, { __typename: 'TimelineCalendarEvent', @@ -71,6 +80,7 @@ export const mockedTimelineCalendarEvents: TimelineCalendarEvent[] = [ handle: 'tim@apple.dev', }, ], + callRecordings: [], }, { __typename: 'TimelineCalendarEvent', @@ -100,5 +110,13 @@ export const mockedTimelineCalendarEvents: TimelineCalendarEvent[] = [ handle: 'tim@apple.dev', }, ], + callRecordings: [ + { + __typename: 'TimelineCalendarEventCallRecording', + id: '20202020-7b1e-4d3a-8f2c-1a9b8c7d6e5f', + status: CallRecordingStatus.SCHEDULED, + applicationId: null, + }, + ], }, ]; diff --git a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-call-recording.dto.ts b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-call-recording.dto.ts new file mode 100644 index 0000000000..74c10285f9 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event-call-recording.dto.ts @@ -0,0 +1,21 @@ +import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; + +import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import { CallRecordingStatus } from 'src/modules/call-recording/common/enums/call-recording-status.enum'; + +registerEnumType(CallRecordingStatus, { + name: 'CallRecordingStatus', + description: 'Recording lifecycle status', +}); + +@ObjectType('TimelineCalendarEventCallRecording') +export class TimelineCalendarEventCallRecordingDTO { + @Field(() => UUIDScalarType) + id: string; + + @Field(() => CallRecordingStatus) + status: CallRecordingStatus; + + @Field(() => UUIDScalarType, { nullable: true }) + applicationId: string | null; +} diff --git a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts index d4e5f65405..c9f0d19203 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/dtos/timeline-calendar-event.dto.ts @@ -2,6 +2,7 @@ import { Field, ObjectType } from '@nestjs/graphql'; import { CalendarChannelVisibility } from 'twenty-shared/types'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import { TimelineCalendarEventCallRecordingDTO } from 'src/engine/core-modules/calendar/dtos/timeline-calendar-event-call-recording.dto'; import { TimelineCalendarEventParticipantDTO } from 'src/engine/core-modules/calendar/dtos/timeline-calendar-event-participant.dto'; @ObjectType('LinkMetadata') @@ -60,6 +61,9 @@ export class TimelineCalendarEventDTO { @Field(() => [TimelineCalendarEventParticipantDTO]) participants: TimelineCalendarEventParticipantDTO[]; + @Field(() => [TimelineCalendarEventCallRecordingDTO]) + callRecordings: TimelineCalendarEventCallRecordingDTO[]; + @Field(() => CalendarChannelVisibility) visibility: CalendarChannelVisibility; } diff --git a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.spec.ts b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.spec.ts index 4da2f6bf84..7358ba1f74 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.spec.ts @@ -31,6 +31,7 @@ describe('TimelineCalendarEventService', () => { let mockUserWorkspaceRepository: { findOne: jest.Mock }; let mockWorkspaceMemberRepository: { findOne: jest.Mock }; let mockFileUrlService: { signFirstFilesFieldFileUrl: jest.Mock }; + let mockCallRecordingRepository: { find: jest.Mock }; const mockCalendarEvent: Partial = { id: '1', @@ -69,6 +70,10 @@ describe('TimelineCalendarEventService', () => { signFirstFilesFieldFileUrl: jest.fn().mockResolvedValue(null), }; + mockCallRecordingRepository = { + find: jest.fn().mockResolvedValue([]), + }; + const mockGlobalWorkspaceOrmManager = { getRepository: jest .fn() @@ -77,6 +82,10 @@ describe('TimelineCalendarEventService', () => { return Promise.resolve(mockWorkspaceMemberRepository); } + if (entityName === 'callRecording') { + return Promise.resolve(mockCallRecordingRepository); + } + return Promise.resolve(mockCalendarEventRepository); }), executeInWorkspaceContext: jest diff --git a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts index 32ef6f239b..14858f7bd7 100644 --- a/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts +++ b/packages/twenty-server/src/engine/core-modules/calendar/timeline-calendar-event.service.ts @@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import omit from 'lodash.omit'; import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/constants'; +import { isDefined } from 'twenty-shared/utils'; import { Any, In, type Repository } from 'typeorm'; import { CalendarChannelVisibility } from 'twenty-shared/types'; @@ -16,6 +17,8 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; import { type CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { type CallRecordingStatus } from 'src/modules/call-recording/common/enums/call-recording-status.enum'; +import { type CallRecordingWorkspaceEntity } from 'src/modules/call-recording/standard-objects/call-recording.workspace-entity'; import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @Injectable() @@ -107,6 +110,50 @@ export class TimelineCalendarEventService { }, }); + const callRecordingRepository = + await this.globalWorkspaceOrmManager.getRepository( + workspaceId, + 'callRecording', + ); + + const callRecordings = await callRecordingRepository.find({ + where: { + calendarEventId: Any(ids), + }, + select: { + id: true, + status: true, + applicationId: true, + calendarEventId: true, + }, + }); + + const callRecordingsByCalendarEventId = callRecordings.reduce< + Map< + string, + { + id: string; + status: CallRecordingStatus; + applicationId: string | null; + }[] + > + >((acc, callRecording) => { + if (!isDefined(callRecording.calendarEventId)) { + return acc; + } + + const existing = acc.get(callRecording.calendarEventId) ?? []; + + existing.push({ + id: callRecording.id, + status: callRecording.status, + applicationId: callRecording.applicationId ?? null, + }); + acc.set(callRecording.calendarEventId, existing); + + return acc; + }, new Map()); + const allCalendarChannelIds = [ ...new Set( events.flatMap((event) => @@ -259,6 +306,8 @@ export class TimelineCalendarEventService { startsAt: event.startsAt as unknown as Date, endsAt: event.endsAt as unknown as Date, participants, + callRecordings: + callRecordingsByCalendarEventId.get(event.id) ?? [], visibility, location: event.location ?? '', conferenceSolution: event.conferenceSolution ?? '', diff --git a/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss b/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss index 075b571fe3..3b65f439b6 100644 --- a/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss +++ b/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss @@ -62,6 +62,26 @@ width: 12px; } +.pulsing { + animation: avatarPulsing 0.8s ease-in-out infinite alternate; +} + +@keyframes avatarPulsing { + from { + opacity: 1; + } + to { + opacity: 0.4; + } +} + +@media (prefers-reduced-motion: reduce) { + .pulsing { + animation: none; + opacity: 1; + } +} + .image { height: 100%; object-fit: cover; diff --git a/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss.d.ts b/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss.d.ts index 52e8e87219..709f85fca7 100644 --- a/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss.d.ts +++ b/packages/twenty-ui/src/data-display/Avatar/Avatar.module.scss.d.ts @@ -5,6 +5,7 @@ declare const classNames: { readonly md: 'md'; readonly sm: 'sm'; readonly xs: 'xs'; + readonly pulsing: 'pulsing'; readonly image: 'image'; readonly placeholderChar: 'placeholderChar'; }; diff --git a/packages/twenty-ui/src/data-display/Avatar/Avatar.tsx b/packages/twenty-ui/src/data-display/Avatar/Avatar.tsx index 618ef2da06..ee1e31b7db 100644 --- a/packages/twenty-ui/src/data-display/Avatar/Avatar.tsx +++ b/packages/twenty-ui/src/data-display/Avatar/Avatar.tsx @@ -24,6 +24,7 @@ export type AvatarProps = { color?: string; backgroundColor?: string; borderColor?: string; + pulsing?: boolean; onClick?: () => void; }; @@ -40,6 +41,7 @@ export const Avatar = ({ color, backgroundColor, borderColor, + pulsing = false, }: AvatarProps) => { const theme = useTheme(); @@ -112,7 +114,12 @@ export const Avatar = ({ return (