feat(server): derive email/calendar timelines from object relations (#21684)
Simplifies our existing implementation that uses three different GraphQL
endpoints to just one `getTimelineEventsFrom{Person, Company,
Opportunity}Id` to `getTimelineCalendarEventsFromObjectRecord`
/closes https://github.com/twentyhq/twenty/issues/19676
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21684?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@@ -259,11 +259,19 @@ export type ObjectRecordFilterInput = {
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
/** @deprecated Use getTimelineCalendarEventsFromObjectRecord instead */
|
||||
getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal;
|
||||
getTimelineCalendarEventsFromObjectRecord: TimelineCalendarEventsWithTotal;
|
||||
/** @deprecated Use getTimelineCalendarEventsFromObjectRecord instead */
|
||||
getTimelineCalendarEventsFromOpportunityId: TimelineCalendarEventsWithTotal;
|
||||
/** @deprecated Use getTimelineCalendarEventsFromObjectRecord instead */
|
||||
getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal;
|
||||
/** @deprecated Use getTimelineThreadsFromObjectRecord instead */
|
||||
getTimelineThreadsFromCompanyId: TimelineThreadsWithTotal;
|
||||
getTimelineThreadsFromObjectRecord: TimelineThreadsWithTotal;
|
||||
/** @deprecated Use getTimelineThreadsFromObjectRecord instead */
|
||||
getTimelineThreadsFromOpportunityId: TimelineThreadsWithTotal;
|
||||
/** @deprecated Use getTimelineThreadsFromObjectRecord instead */
|
||||
getTimelineThreadsFromPersonId: TimelineThreadsWithTotal;
|
||||
isMaintenanceModeBannerDismissed: Scalars['Boolean']['output'];
|
||||
search: SearchResultConnection;
|
||||
@@ -278,6 +286,14 @@ export type QueryGetTimelineCalendarEventsFromCompanyIdArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetTimelineCalendarEventsFromObjectRecordArgs = {
|
||||
objectNameSingular: Scalars['String']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
recordId: Scalars['UUID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetTimelineCalendarEventsFromOpportunityIdArgs = {
|
||||
opportunityId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
@@ -299,6 +315,14 @@ export type QueryGetTimelineThreadsFromCompanyIdArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetTimelineThreadsFromObjectRecordArgs = {
|
||||
objectNameSingular: Scalars['String']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
recordId: Scalars['UUID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryGetTimelineThreadsFromOpportunityIdArgs = {
|
||||
opportunityId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
@@ -594,32 +618,15 @@ export type TimelineCalendarEventParticipantFragmentFragment = { __typename?: 'T
|
||||
|
||||
export type TimelineCalendarEventsWithTotalFragmentFragment = { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, 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 GetTimelineCalendarEventsFromCompanyIdQueryVariables = Exact<{
|
||||
companyId: Scalars['UUID']['input'];
|
||||
export type GetTimelineCalendarEventsFromObjectRecordQueryVariables = Exact<{
|
||||
objectNameSingular: Scalars['String']['input'];
|
||||
recordId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineCalendarEventsFromCompanyIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromCompanyId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, 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 GetTimelineCalendarEventsFromOpportunityIdQueryVariables = Exact<{
|
||||
opportunityId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineCalendarEventsFromOpportunityIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromOpportunityId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, 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 GetTimelineCalendarEventsFromPersonIdQueryVariables = Exact<{
|
||||
personId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineCalendarEventsFromPersonIdQuery = { __typename?: 'Query', getTimelineCalendarEventsFromPersonId: { __typename?: 'TimelineCalendarEventsWithTotal', totalNumberOfCalendarEvents: number, 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, 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 ParticipantFragmentFragment = { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string };
|
||||
|
||||
@@ -627,32 +634,15 @@ export type TimelineThreadFragmentFragment = { __typename?: 'TimelineThread', id
|
||||
|
||||
export type TimelineThreadsWithTotalFragmentFragment = { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> };
|
||||
|
||||
export type GetTimelineThreadsFromCompanyIdQueryVariables = Exact<{
|
||||
companyId: Scalars['UUID']['input'];
|
||||
export type GetTimelineThreadsFromObjectRecordQueryVariables = Exact<{
|
||||
objectNameSingular: Scalars['String']['input'];
|
||||
recordId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineThreadsFromCompanyIdQuery = { __typename?: 'Query', getTimelineThreadsFromCompanyId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
|
||||
export type GetTimelineThreadsFromOpportunityIdQueryVariables = Exact<{
|
||||
opportunityId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineThreadsFromOpportunityIdQuery = { __typename?: 'Query', getTimelineThreadsFromOpportunityId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
|
||||
export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
|
||||
personId: Scalars['UUID']['input'];
|
||||
page: Scalars['Int']['input'];
|
||||
pageSize: Scalars['Int']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
export type GetTimelineThreadsFromObjectRecordQuery = { __typename?: 'Query', getTimelineThreadsFromObjectRecord: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
|
||||
export type SearchQueryVariables = Exact<{
|
||||
searchInput: Scalars['String']['input'];
|
||||
@@ -808,12 +798,8 @@ export const ParticipantFragmentFragmentDoc = {"kind":"Document","definitions":[
|
||||
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":"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<TimelineThreadFragmentFragment, unknown>;
|
||||
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":"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"}}]}}]} as unknown as DocumentNode<TimelineThreadsWithTotalFragmentFragment, unknown>;
|
||||
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<WorkflowDiffFragmentFragment, unknown>;
|
||||
export const GetTimelineCalendarEventsFromCompanyIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineCalendarEventsFromCompanyId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"companyId"}},"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":"getTimelineCalendarEventsFromCompanyId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"companyId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"companyId"}}},{"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":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineCalendarEventsFromCompanyIdQuery, GetTimelineCalendarEventsFromCompanyIdQueryVariables>;
|
||||
export const GetTimelineCalendarEventsFromOpportunityIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineCalendarEventsFromOpportunityId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"opportunityId"}},"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":"getTimelineCalendarEventsFromOpportunityId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"opportunityId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"opportunityId"}}},{"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":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineCalendarEventsFromOpportunityIdQuery, GetTimelineCalendarEventsFromOpportunityIdQueryVariables>;
|
||||
export const GetTimelineCalendarEventsFromPersonIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineCalendarEventsFromPersonId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"personId"}},"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":"getTimelineCalendarEventsFromPersonId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"personId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"personId"}}},{"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":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineCalendarEventsFromPersonIdQuery, GetTimelineCalendarEventsFromPersonIdQueryVariables>;
|
||||
export const GetTimelineThreadsFromCompanyIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineThreadsFromCompanyId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"companyId"}},"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":"getTimelineThreadsFromCompanyId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"companyId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"companyId"}}},{"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":"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":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineThreadsFromCompanyIdQuery, GetTimelineThreadsFromCompanyIdQueryVariables>;
|
||||
export const GetTimelineThreadsFromOpportunityIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineThreadsFromOpportunityId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"opportunityId"}},"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":"getTimelineThreadsFromOpportunityId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"opportunityId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"opportunityId"}}},{"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":"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":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineThreadsFromOpportunityIdQuery, GetTimelineThreadsFromOpportunityIdQueryVariables>;
|
||||
export const GetTimelineThreadsFromPersonIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTimelineThreadsFromPersonId"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"personId"}},"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":"getTimelineThreadsFromPersonId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"personId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"personId"}}},{"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":"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":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineThreadsFromPersonIdQuery, GetTimelineThreadsFromPersonIdQueryVariables>;
|
||||
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":"timelineCalendarEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineCalendarEventFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineCalendarEventsFromObjectRecordQuery, GetTimelineCalendarEventsFromObjectRecordQueryVariables>;
|
||||
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":"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":"timelineThreads"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"TimelineThreadFragment"}}]}}]}}]} as unknown as DocumentNode<GetTimelineThreadsFromObjectRecordQuery, GetTimelineThreadsFromObjectRecordQueryVariables>;
|
||||
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<SearchQuery, SearchQueryVariables>;
|
||||
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<ActivateWorkflowVersionMutation, ActivateWorkflowVersionMutationVariables>;
|
||||
export const ComputeStepOutputSchemaDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ComputeStepOutputSchema"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ComputeStepOutputSchemaInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"computeStepOutputSchema"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}]}]}}]} as unknown as DocumentNode<ComputeStepOutputSchemaMutation, ComputeStepOutputSchemaMutationVariables>;
|
||||
|
||||
+4
-23
@@ -6,14 +6,11 @@ import { format, getYear } from 'date-fns';
|
||||
import { CalendarMonthCard } from '@/activities/calendar/components/CalendarMonthCard';
|
||||
import { TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE } from '@/activities/calendar/constants/Calendar';
|
||||
import { CalendarContext } from '@/activities/calendar/contexts/CalendarContext';
|
||||
import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId';
|
||||
import { getTimelineCalendarEventsFromOpportunityId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromOpportunityId';
|
||||
import { getTimelineCalendarEventsFromPersonId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromPersonId';
|
||||
import { getTimelineCalendarEventsFromObjectRecord } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromObjectRecord';
|
||||
import { useCalendarEvents } from '@/activities/calendar/hooks/useCalendarEvents';
|
||||
import { CustomResolverFetchMoreLoader } from '@/activities/components/CustomResolverFetchMoreLoader';
|
||||
import { SkeletonLoader } from '@/activities/components/SkeletonLoader';
|
||||
import { useCustomResolver } from '@/activities/hooks/useCustomResolver';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { H3Title } from 'twenty-ui/typography';
|
||||
import {
|
||||
@@ -52,33 +49,17 @@ export const CalendarEventsCard = () => {
|
||||
const targetRecord = useTargetRecord();
|
||||
const { localeCatalog } = useAtomStateValue(dateLocaleState);
|
||||
|
||||
const [query, queryName] =
|
||||
targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Person
|
||||
? [
|
||||
getTimelineCalendarEventsFromPersonId,
|
||||
'getTimelineCalendarEventsFromPersonId',
|
||||
]
|
||||
: targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Company
|
||||
? [
|
||||
getTimelineCalendarEventsFromCompanyId,
|
||||
'getTimelineCalendarEventsFromCompanyId',
|
||||
]
|
||||
: [
|
||||
getTimelineCalendarEventsFromOpportunityId,
|
||||
'getTimelineCalendarEventsFromOpportunityId',
|
||||
];
|
||||
|
||||
const { data, firstQueryLoading, isFetchingMore, fetchMoreRecords } =
|
||||
useCustomResolver<TimelineCalendarEventsWithTotal>(
|
||||
query,
|
||||
queryName,
|
||||
getTimelineCalendarEventsFromObjectRecord,
|
||||
'getTimelineCalendarEventsFromObjectRecord',
|
||||
'timelineCalendarEvents',
|
||||
targetRecord,
|
||||
TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE,
|
||||
);
|
||||
|
||||
const { timelineCalendarEvents, totalNumberOfCalendarEvents } =
|
||||
data?.[queryName] ?? {};
|
||||
data?.getTimelineCalendarEventsFromObjectRecord ?? {};
|
||||
|
||||
const {
|
||||
calendarEventsByDayTime,
|
||||
|
||||
+4
-4
@@ -3,7 +3,7 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { HttpResponse, graphql } from 'msw';
|
||||
|
||||
import { CalendarEventsCard } from '@/activities/calendar/components/CalendarEventsCard';
|
||||
import { getTimelineCalendarEventsFromCompanyId } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromCompanyId';
|
||||
import { getTimelineCalendarEventsFromObjectRecord } from '@/activities/calendar/graphql/queries/getTimelineCalendarEventsFromObjectRecord';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
@@ -41,12 +41,12 @@ const meta: Meta<typeof CalendarEventsCard> = {
|
||||
handlers: [
|
||||
...graphqlMocks.handlers,
|
||||
graphql.query(
|
||||
getOperationName(getTimelineCalendarEventsFromCompanyId) ?? '',
|
||||
getOperationName(getTimelineCalendarEventsFromObjectRecord) ?? '',
|
||||
({ variables }) => {
|
||||
if (variables.page > 1) {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
getTimelineCalendarEventsFromCompanyId: {
|
||||
getTimelineCalendarEventsFromObjectRecord: {
|
||||
__typename: 'TimelineCalendarEventsWithTotal',
|
||||
totalNumberOfCalendarEvents: 3,
|
||||
timelineCalendarEvents: [],
|
||||
@@ -56,7 +56,7 @@ const meta: Meta<typeof CalendarEventsCard> = {
|
||||
}
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
getTimelineCalendarEventsFromCompanyId: {
|
||||
getTimelineCalendarEventsFromObjectRecord: {
|
||||
__typename: 'TimelineCalendarEventsWithTotal',
|
||||
totalNumberOfCalendarEvents: 3,
|
||||
timelineCalendarEvents: mockedTimelineCalendarEvents,
|
||||
|
||||
+7
-5
@@ -1,14 +1,16 @@
|
||||
import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const getTimelineCalendarEventsFromCompanyId = gql`
|
||||
query GetTimelineCalendarEventsFromCompanyId(
|
||||
$companyId: UUID!
|
||||
export const getTimelineCalendarEventsFromObjectRecord = gql`
|
||||
query GetTimelineCalendarEventsFromObjectRecord(
|
||||
$objectNameSingular: String!
|
||||
$recordId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineCalendarEventsFromCompanyId(
|
||||
companyId: $companyId
|
||||
getTimelineCalendarEventsFromObjectRecord(
|
||||
objectNameSingular: $objectNameSingular
|
||||
recordId: $recordId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment';
|
||||
|
||||
export const getTimelineCalendarEventsFromOpportunityId = gql`
|
||||
query GetTimelineCalendarEventsFromOpportunityId(
|
||||
$opportunityId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineCalendarEventsFromOpportunityId(
|
||||
opportunityId: $opportunityId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineCalendarEventsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineCalendarEventWithTotalFragment}
|
||||
`;
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import { timelineCalendarEventWithTotalFragment } from '@/activities/calendar/graphql/queries/fragments/timelineCalendarEventWithTotalFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const getTimelineCalendarEventsFromPersonId = gql`
|
||||
query GetTimelineCalendarEventsFromPersonId(
|
||||
$personId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineCalendarEventsFromPersonId(
|
||||
personId: $personId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineCalendarEventsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineCalendarEventWithTotalFragment}
|
||||
`;
|
||||
@@ -7,11 +7,8 @@ import { ComposeEmailButton } from '@/activities/emails/components/ComposeEmailB
|
||||
import { EmailThreadPreview } from '@/activities/emails/components/EmailThreadPreview';
|
||||
import { EmptyInboxPlaceholder } from '@/activities/emails/components/EmptyInboxPlaceholder';
|
||||
import { TIMELINE_THREADS_DEFAULT_PAGE_SIZE } from '@/activities/emails/constants/Messaging';
|
||||
import { getTimelineThreadsFromCompanyId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId';
|
||||
import { getTimelineThreadsFromOpportunityId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromOpportunityId';
|
||||
import { getTimelineThreadsFromPersonId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromPersonId';
|
||||
import { getTimelineThreadsFromObjectRecord } from '@/activities/emails/graphql/queries/getTimelineThreadsFromObjectRecord';
|
||||
import { useCustomResolver } from '@/activities/hooks/useCustomResolver';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
import { H1Title, H1TitleFontColor } from 'twenty-ui/typography';
|
||||
@@ -52,26 +49,17 @@ const StyledEmailCount = styled.span`
|
||||
export const EmailsCard = () => {
|
||||
const targetRecord = useTargetRecord();
|
||||
|
||||
const [query, queryName] =
|
||||
targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Person
|
||||
? [getTimelineThreadsFromPersonId, 'getTimelineThreadsFromPersonId']
|
||||
: targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Company
|
||||
? [getTimelineThreadsFromCompanyId, 'getTimelineThreadsFromCompanyId']
|
||||
: [
|
||||
getTimelineThreadsFromOpportunityId,
|
||||
'getTimelineThreadsFromOpportunityId',
|
||||
];
|
||||
|
||||
const { data, firstQueryLoading, isFetchingMore, fetchMoreRecords } =
|
||||
useCustomResolver<TimelineThreadsWithTotal>(
|
||||
query,
|
||||
queryName,
|
||||
getTimelineThreadsFromObjectRecord,
|
||||
'getTimelineThreadsFromObjectRecord',
|
||||
'timelineThreads',
|
||||
targetRecord,
|
||||
TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
|
||||
);
|
||||
|
||||
const { totalNumberOfThreads, timelineThreads } = data?.[queryName] ?? {};
|
||||
const { totalNumberOfThreads, timelineThreads } =
|
||||
data?.getTimelineThreadsFromObjectRecord ?? {};
|
||||
const hasMoreTimelineThreads =
|
||||
timelineThreads && totalNumberOfThreads
|
||||
? timelineThreads?.length < totalNumberOfThreads
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { getTimelineThreadsFromCompanyId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId';
|
||||
|
||||
jest.mock('@apollo/client', () => ({
|
||||
gql: jest.fn().mockImplementation((strings) => {
|
||||
return strings.map((str: string) => str.trim()).join(' ');
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('getTimelineThreadsFromCompanyId query', () => {
|
||||
test('should construct the query correctly', () => {
|
||||
expect(gql).toHaveBeenCalled();
|
||||
expect(getTimelineThreadsFromCompanyId).toBeDefined();
|
||||
});
|
||||
});
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { getTimelineThreadsFromPersonId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromPersonId';
|
||||
|
||||
jest.mock('@apollo/client', () => ({
|
||||
gql: jest.fn().mockImplementation((strings) => {
|
||||
return strings.map((str: string) => str.trim()).join(' ');
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('getTimelineThreadsFromPersonId query', () => {
|
||||
test('should construct the query correctly', () => {
|
||||
expect(gql).toHaveBeenCalled();
|
||||
expect(getTimelineThreadsFromPersonId).toBeDefined();
|
||||
});
|
||||
});
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const getTimelineThreadsFromCompanyId = gql`
|
||||
query GetTimelineThreadsFromCompanyId(
|
||||
$companyId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineThreadsFromCompanyId(
|
||||
companyId: $companyId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineThreadWithTotalFragment}
|
||||
`;
|
||||
+8
-7
@@ -1,15 +1,16 @@
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment';
|
||||
|
||||
export const getTimelineThreadsFromOpportunityId = gql`
|
||||
query GetTimelineThreadsFromOpportunityId(
|
||||
$opportunityId: UUID!
|
||||
export const getTimelineThreadsFromObjectRecord = gql`
|
||||
query GetTimelineThreadsFromObjectRecord(
|
||||
$objectNameSingular: String!
|
||||
$recordId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineThreadsFromOpportunityId(
|
||||
opportunityId: $opportunityId
|
||||
getTimelineThreadsFromObjectRecord(
|
||||
objectNameSingular: $objectNameSingular
|
||||
recordId: $recordId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/graphql/queries/fragments/timelineThreadWithTotalFragment';
|
||||
|
||||
export const getTimelineThreadsFromPersonId = gql`
|
||||
query GetTimelineThreadsFromPersonId(
|
||||
$personId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineThreadsFromPersonId(
|
||||
personId: $personId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineThreadWithTotalFragment}
|
||||
`;
|
||||
@@ -3,9 +3,7 @@ import { useCallback } from 'react';
|
||||
import { type EmailAttachment } from 'twenty-shared/types';
|
||||
|
||||
import { SEND_EMAIL } from '@/activities/emails/graphql/mutations/sendEmail';
|
||||
import { getTimelineThreadsFromCompanyId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromCompanyId';
|
||||
import { getTimelineThreadsFromOpportunityId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromOpportunityId';
|
||||
import { getTimelineThreadsFromPersonId } from '@/activities/emails/graphql/queries/getTimelineThreadsFromPersonId';
|
||||
import { getTimelineThreadsFromObjectRecord } from '@/activities/emails/graphql/queries/getTimelineThreadsFromObjectRecord';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { t } from '@lingui/core/macro';
|
||||
@@ -60,9 +58,7 @@ export const useSendEmail = () => {
|
||||
|
||||
await apolloCoreClient.refetchQueries({
|
||||
include: [
|
||||
getTimelineThreadsFromCompanyId,
|
||||
getTimelineThreadsFromPersonId,
|
||||
getTimelineThreadsFromOpportunityId,
|
||||
getTimelineThreadsFromObjectRecord,
|
||||
'FindManyMessages',
|
||||
'FindManyMessageParticipants',
|
||||
'FindManyMessageChannelMessageAssociations',
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { getTimelineThreadsFromObjectRecord } from '@/activities/emails/graphql/queries/getTimelineThreadsFromObjectRecord';
|
||||
import { useCustomResolver } from '@/activities/hooks/useCustomResolver';
|
||||
|
||||
jest.mock('@apollo/client/react', () => ({
|
||||
useQuery: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@/object-metadata/hooks/useApolloCoreClient', () => ({
|
||||
useApolloCoreClient: jest.fn(() => ({})),
|
||||
}));
|
||||
|
||||
jest.mock('@/apollo/hooks/useSnackBarOnQueryError', () => ({
|
||||
useSnackBarOnQueryError: jest.fn(),
|
||||
}));
|
||||
|
||||
const useQueryMock = jest.requireMock('@apollo/client/react').useQuery;
|
||||
|
||||
describe('useCustomResolver', () => {
|
||||
beforeEach(() => {
|
||||
useQueryMock.mockReturnValue({
|
||||
data: undefined,
|
||||
loading: false,
|
||||
fetchMore: jest.fn(),
|
||||
error: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('queries the timeline resolver by object name and record id for any object', () => {
|
||||
renderHook(() =>
|
||||
useCustomResolver(
|
||||
getTimelineThreadsFromObjectRecord,
|
||||
'getTimelineThreadsFromObjectRecord',
|
||||
'timelineThreads',
|
||||
{ id: 'record-id', targetObjectNameSingular: 'peopleList' },
|
||||
10,
|
||||
),
|
||||
);
|
||||
|
||||
expect(useQueryMock).toHaveBeenCalledWith(
|
||||
getTimelineThreadsFromObjectRecord,
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
objectNameSingular: 'peopleList',
|
||||
recordId: 'record-id',
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -9,7 +9,6 @@ import { useState } from 'react';
|
||||
import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { useSnackBarOnQueryError } from '@/apollo/hooks/useSnackBarOnQueryError';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
type CustomResolverQueryResult<
|
||||
T extends {
|
||||
@@ -47,13 +46,8 @@ export const useCustomResolver = <
|
||||
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
||||
|
||||
const queryVariables = {
|
||||
...(activityTargetableObject.targetObjectNameSingular ===
|
||||
CoreObjectNameSingular.Person
|
||||
? { personId: activityTargetableObject.id }
|
||||
: activityTargetableObject.targetObjectNameSingular ===
|
||||
CoreObjectNameSingular.Opportunity
|
||||
? { opportunityId: activityTargetableObject.id }
|
||||
: { companyId: activityTargetableObject.id }),
|
||||
objectNameSingular: activityTargetableObject.targetObjectNameSingular,
|
||||
recordId: activityTargetableObject.id,
|
||||
page: 1,
|
||||
pageSize,
|
||||
};
|
||||
|
||||
+2
@@ -4,6 +4,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TimelineCalendarEventResolver } from 'src/engine/core-modules/calendar/timeline-calendar-event.resolver';
|
||||
import { TimelineCalendarEventService } from 'src/engine/core-modules/calendar/timeline-calendar-event.service';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { RelatedPersonIdsModule } from 'src/engine/core-modules/related-person-ids/related-person-ids.module';
|
||||
import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity';
|
||||
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
|
||||
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||
@@ -11,6 +12,7 @@ import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||
@Module({
|
||||
imports: [
|
||||
UserModule,
|
||||
RelatedPersonIdsModule,
|
||||
TypeOrmModule.forFeature([
|
||||
CalendarChannelEntity,
|
||||
ConnectedAccountEntity,
|
||||
|
||||
+71
-34
@@ -2,6 +2,7 @@ import { UseGuards } from '@nestjs/common';
|
||||
import { Args, ArgsType, Field, Int, Query } from '@nestjs/graphql';
|
||||
|
||||
import { Max } from 'class-validator';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { TIMELINE_CALENDAR_EVENTS_MAX_PAGE_SIZE } from 'src/engine/core-modules/calendar/constants/calendar.constants';
|
||||
@@ -14,6 +15,22 @@ import { CustomPermissionGuard } from 'src/engine/guards/custom-permission.guard
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@ArgsType()
|
||||
class GetTimelineCalendarEventsFromObjectRecordArgs {
|
||||
@Field(() => String)
|
||||
objectNameSingular: string;
|
||||
|
||||
@Field(() => UUIDScalarType)
|
||||
recordId: string;
|
||||
|
||||
@Field(() => Int)
|
||||
page: number;
|
||||
|
||||
@Field(() => Int)
|
||||
@Max(TIMELINE_CALENDAR_EVENTS_MAX_PAGE_SIZE)
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
class GetTimelineCalendarEventsFromPersonIdArgs {
|
||||
@Field(() => UUIDScalarType)
|
||||
@@ -61,44 +78,68 @@ export class TimelineCalendarEventResolver {
|
||||
) {}
|
||||
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO)
|
||||
async getTimelineCalendarEventsFromObjectRecord(
|
||||
@Args()
|
||||
{
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
page,
|
||||
pageSize,
|
||||
}: GetTimelineCalendarEventsFromObjectRecordArgs,
|
||||
@AuthWorkspaceMemberId() workspaceMemberId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
return this.timelineCalendarEventService.getCalendarEventsFromObjectRecord({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineCalendarEventsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineCalendarEventsFromPersonId(
|
||||
@Args()
|
||||
{ personId, page, pageSize }: GetTimelineCalendarEventsFromPersonIdArgs,
|
||||
@AuthWorkspaceMemberId() workspaceMemberId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
const timelineCalendarEvents =
|
||||
await this.timelineCalendarEventService.getCalendarEventsFromPersonIds({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
personIds: [personId],
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
|
||||
return timelineCalendarEvents;
|
||||
return this.timelineCalendarEventService.getCalendarEventsFromObjectRecord({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
objectNameSingular: CoreObjectNameSingular.Person,
|
||||
recordId: personId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO)
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineCalendarEventsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineCalendarEventsFromCompanyId(
|
||||
@Args()
|
||||
{ companyId, page, pageSize }: GetTimelineCalendarEventsFromCompanyIdArgs,
|
||||
@AuthWorkspaceMemberId() workspaceMemberId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
const timelineCalendarEvents =
|
||||
await this.timelineCalendarEventService.getCalendarEventsFromCompanyId({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
companyId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
|
||||
return timelineCalendarEvents;
|
||||
return this.timelineCalendarEventService.getCalendarEventsFromObjectRecord({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
objectNameSingular: CoreObjectNameSingular.Company,
|
||||
recordId: companyId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO)
|
||||
@Query(() => TimelineCalendarEventsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineCalendarEventsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineCalendarEventsFromOpportunityId(
|
||||
@Args()
|
||||
{
|
||||
@@ -109,17 +150,13 @@ export class TimelineCalendarEventResolver {
|
||||
@AuthWorkspaceMemberId() workspaceMemberId: string,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
const timelineCalendarEvents =
|
||||
await this.timelineCalendarEventService.getCalendarEventsFromOpportunityId(
|
||||
{
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
opportunityId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
},
|
||||
);
|
||||
|
||||
return timelineCalendarEvents;
|
||||
return this.timelineCalendarEventService.getCalendarEventsFromObjectRecord({
|
||||
currentWorkspaceMemberId: workspaceMemberId,
|
||||
objectNameSingular: CoreObjectNameSingular.Opportunity,
|
||||
recordId: opportunityId,
|
||||
workspaceId: workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -5,6 +5,7 @@ import { FIELD_RESTRICTED_ADDITIONAL_PERMISSIONS_REQUIRED } from 'twenty-shared/
|
||||
|
||||
import { CalendarChannelVisibility } from 'twenty-shared/types';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { RelatedPersonIdsService } from 'src/engine/core-modules/related-person-ids/services/related-person-ids.service';
|
||||
import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity';
|
||||
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
@@ -96,6 +97,10 @@ describe('TimelineCalendarEventService', () => {
|
||||
provide: getRepositoryToken(UserWorkspaceEntity),
|
||||
useValue: mockUserWorkspaceRepository,
|
||||
},
|
||||
{
|
||||
provide: RelatedPersonIdsService,
|
||||
useValue: { getRelatedPersonIds: jest.fn().mockResolvedValue([]) },
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
+25
-98
@@ -8,14 +8,13 @@ import { Any, In, type Repository } from 'typeorm';
|
||||
import { CalendarChannelVisibility } from 'twenty-shared/types';
|
||||
import { TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE } from 'src/engine/core-modules/calendar/constants/calendar.constants';
|
||||
import { type TimelineCalendarEventsWithTotalDTO } from 'src/engine/core-modules/calendar/dtos/timeline-calendar-events-with-total.dto';
|
||||
import { RelatedPersonIdsService } from 'src/engine/core-modules/related-person-ids/services/related-person-ids.service';
|
||||
import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity';
|
||||
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
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 OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
|
||||
import { type PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -28,6 +27,7 @@ export class TimelineCalendarEventService {
|
||||
private readonly connectedAccountRepository: Repository<ConnectedAccountEntity>,
|
||||
@InjectRepository(UserWorkspaceEntity)
|
||||
private readonly userWorkspaceRepository: Repository<UserWorkspaceEntity>,
|
||||
private readonly relatedPersonIdsService: RelatedPersonIdsService,
|
||||
) {}
|
||||
|
||||
async getCalendarEventsFromPersonIds({
|
||||
@@ -259,113 +259,40 @@ export class TimelineCalendarEventService {
|
||||
);
|
||||
}
|
||||
|
||||
async getCalendarEventsFromCompanyId({
|
||||
async getCalendarEventsFromObjectRecord({
|
||||
currentWorkspaceMemberId,
|
||||
companyId,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
workspaceId,
|
||||
page = 1,
|
||||
pageSize = TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE,
|
||||
}: {
|
||||
currentWorkspaceMemberId: string;
|
||||
companyId: string;
|
||||
objectNameSingular: string;
|
||||
recordId: string;
|
||||
workspaceId: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<TimelineCalendarEventsWithTotalDTO> {
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
const personIds = await this.relatedPersonIdsService.getRelatedPersonIds({
|
||||
workspaceId,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
});
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const personRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<PersonWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'person',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
if (personIds.length === 0) {
|
||||
return {
|
||||
totalNumberOfCalendarEvents: 0,
|
||||
timelineCalendarEvents: [],
|
||||
};
|
||||
}
|
||||
|
||||
const personIds = await personRepository.find({
|
||||
where: {
|
||||
companyId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (personIds.length <= 0) {
|
||||
return {
|
||||
totalNumberOfCalendarEvents: 0,
|
||||
timelineCalendarEvents: [],
|
||||
};
|
||||
}
|
||||
|
||||
const formattedPersonIds = personIds.map(({ id }) => id);
|
||||
|
||||
const calendarEvents = await this.getCalendarEventsFromPersonIds({
|
||||
currentWorkspaceMemberId,
|
||||
personIds: formattedPersonIds,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
|
||||
return calendarEvents;
|
||||
},
|
||||
authContext,
|
||||
);
|
||||
}
|
||||
|
||||
async getCalendarEventsFromOpportunityId({
|
||||
currentWorkspaceMemberId,
|
||||
opportunityId,
|
||||
workspaceId,
|
||||
page = 1,
|
||||
pageSize = TIMELINE_CALENDAR_EVENTS_DEFAULT_PAGE_SIZE,
|
||||
}: {
|
||||
currentWorkspaceMemberId: string;
|
||||
opportunityId: string;
|
||||
workspaceId: string;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}): Promise<TimelineCalendarEventsWithTotalDTO> {
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const opportunityRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<OpportunityWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'opportunity',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const opportunity = await opportunityRepository.findOne({
|
||||
where: {
|
||||
id: opportunityId,
|
||||
},
|
||||
select: {
|
||||
companyId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!opportunity?.companyId) {
|
||||
return {
|
||||
totalNumberOfCalendarEvents: 0,
|
||||
timelineCalendarEvents: [],
|
||||
};
|
||||
}
|
||||
|
||||
const calendarEvents = await this.getCalendarEventsFromCompanyId({
|
||||
currentWorkspaceMemberId,
|
||||
companyId: opportunity.companyId,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
|
||||
return calendarEvents;
|
||||
},
|
||||
authContext,
|
||||
);
|
||||
return this.getCalendarEventsFromPersonIds({
|
||||
currentWorkspaceMemberId,
|
||||
personIds,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+22
-92
@@ -4,16 +4,13 @@ import { TIMELINE_THREADS_DEFAULT_PAGE_SIZE } from 'src/engine/core-modules/mess
|
||||
import { type TimelineThreadsWithTotalDTO } from 'src/engine/core-modules/messaging/dtos/timeline-threads-with-total.dto';
|
||||
import { TimelineMessagingService } from 'src/engine/core-modules/messaging/services/timeline-messaging.service';
|
||||
import { formatThreads } from 'src/engine/core-modules/messaging/utils/format-threads.util';
|
||||
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 OpportunityWorkspaceEntity } from 'src/modules/opportunity/standard-objects/opportunity.workspace-entity';
|
||||
import { type PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
import { RelatedPersonIdsService } from 'src/engine/core-modules/related-person-ids/services/related-person-ids.service';
|
||||
|
||||
@Injectable()
|
||||
export class GetMessagesService {
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly timelineMessagingService: TimelineMessagingService,
|
||||
private readonly relatedPersonIdsService: RelatedPersonIdsService,
|
||||
) {}
|
||||
|
||||
async getMessagesFromPersonIds(
|
||||
@@ -67,100 +64,33 @@ export class GetMessagesService {
|
||||
};
|
||||
}
|
||||
|
||||
async getMessagesFromCompanyId(
|
||||
async getMessagesFromObjectRecord(
|
||||
workspaceMemberId: string,
|
||||
companyId: string,
|
||||
objectNameSingular: string,
|
||||
recordId: string,
|
||||
workspaceId: string,
|
||||
page = 1,
|
||||
pageSize: number = TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
|
||||
): Promise<TimelineThreadsWithTotalDTO> {
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
const personIds = await this.relatedPersonIdsService.getRelatedPersonIds({
|
||||
workspaceId,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
});
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const personRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<PersonWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'person',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
const personIds = (
|
||||
await personRepository.find({
|
||||
where: {
|
||||
companyId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
})
|
||||
).map((person) => person.id);
|
||||
if (personIds.length === 0) {
|
||||
return {
|
||||
totalNumberOfThreads: 0,
|
||||
timelineThreads: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (personIds.length === 0) {
|
||||
return {
|
||||
totalNumberOfThreads: 0,
|
||||
timelineThreads: [],
|
||||
};
|
||||
}
|
||||
|
||||
const messageThreads = await this.getMessagesFromPersonIds(
|
||||
workspaceMemberId,
|
||||
personIds,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return messageThreads;
|
||||
},
|
||||
authContext,
|
||||
);
|
||||
}
|
||||
|
||||
async getMessagesFromOpportunityId(
|
||||
workspaceMemberId: string,
|
||||
opportunityId: string,
|
||||
workspaceId: string,
|
||||
page = 1,
|
||||
pageSize: number = TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
|
||||
): Promise<TimelineThreadsWithTotalDTO> {
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const opportunityRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<OpportunityWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'opportunity',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const opportunity = await opportunityRepository.findOne({
|
||||
where: {
|
||||
id: opportunityId,
|
||||
},
|
||||
select: {
|
||||
companyId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!opportunity?.companyId) {
|
||||
return {
|
||||
totalNumberOfThreads: 0,
|
||||
timelineThreads: [],
|
||||
};
|
||||
}
|
||||
|
||||
const messageThreads = await this.getMessagesFromCompanyId(
|
||||
workspaceMemberId,
|
||||
opportunity.companyId,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return messageThreads;
|
||||
},
|
||||
authContext,
|
||||
return this.getMessagesFromPersonIds(
|
||||
workspaceMemberId,
|
||||
personIds,
|
||||
workspaceId,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { GetMessagesService } from 'src/engine/core-modules/messaging/services/get-messages.service';
|
||||
import { TimelineMessagingService } from 'src/engine/core-modules/messaging/services/timeline-messaging.service';
|
||||
import { TimelineMessagingResolver } from 'src/engine/core-modules/messaging/timeline-messaging.resolver';
|
||||
import { RelatedPersonIdsModule } from 'src/engine/core-modules/related-person-ids/related-person-ids.module';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { UserModule } from 'src/engine/core-modules/user/user.module';
|
||||
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
|
||||
@@ -20,6 +21,7 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
|
||||
ConnectedAccountModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
RelatedPersonIdsModule,
|
||||
TypeOrmModule.forFeature([
|
||||
MessageChannelEntity,
|
||||
ConnectedAccountEntity,
|
||||
|
||||
+80
-32
@@ -3,6 +3,7 @@ import { Args, ArgsType, Field, Int, Mutation, Query } from '@nestjs/graphql';
|
||||
|
||||
import { Max } from 'class-validator';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
import { CoreResolver } from 'src/engine/api/graphql/graphql-config/decorators/core-resolver.decorator';
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
@@ -21,6 +22,22 @@ import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.g
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service';
|
||||
|
||||
@ArgsType()
|
||||
class GetTimelineThreadsFromObjectRecordArgs {
|
||||
@Field(() => String)
|
||||
objectNameSingular: string;
|
||||
|
||||
@Field(() => UUIDScalarType)
|
||||
recordId: string;
|
||||
|
||||
@Field(() => Int)
|
||||
page: number;
|
||||
|
||||
@Field(() => Int)
|
||||
@Max(TIMELINE_THREADS_MAX_PAGE_SIZE)
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
@ArgsType()
|
||||
class GetTimelineThreadsFromPersonIdArgs {
|
||||
@Field(() => UUIDScalarType)
|
||||
@@ -70,6 +87,39 @@ export class TimelineMessagingResolver {
|
||||
) {}
|
||||
|
||||
@Query(() => TimelineThreadsWithTotalDTO)
|
||||
async getTimelineThreadsFromObjectRecord(
|
||||
@AuthUser() user: AuthContextUser,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@Args()
|
||||
{
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
page,
|
||||
pageSize,
|
||||
}: GetTimelineThreadsFromObjectRecordArgs,
|
||||
) {
|
||||
const workspaceMember = await this.userService.loadWorkspaceMember(
|
||||
user,
|
||||
workspace,
|
||||
);
|
||||
|
||||
if (!workspaceMember) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.getMessagesFromPersonIdsService.getMessagesFromObjectRecord(
|
||||
workspaceMember.id,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
}
|
||||
|
||||
@Query(() => TimelineThreadsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineThreadsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineThreadsFromPersonId(
|
||||
@AuthUser() user: AuthContextUser,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -84,19 +134,19 @@ export class TimelineMessagingResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
const timelineThreads =
|
||||
await this.getMessagesFromPersonIdsService.getMessagesFromPersonIds(
|
||||
workspaceMember.id,
|
||||
[personId],
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return timelineThreads;
|
||||
return this.getMessagesFromPersonIdsService.getMessagesFromObjectRecord(
|
||||
workspaceMember.id,
|
||||
CoreObjectNameSingular.Person,
|
||||
personId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
}
|
||||
|
||||
@Query(() => TimelineThreadsWithTotalDTO)
|
||||
@Query(() => TimelineThreadsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineThreadsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineThreadsFromCompanyId(
|
||||
@AuthUser() user: AuthContextUser,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -111,19 +161,19 @@ export class TimelineMessagingResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
const timelineThreads =
|
||||
await this.getMessagesFromPersonIdsService.getMessagesFromCompanyId(
|
||||
workspaceMember.id,
|
||||
companyId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return timelineThreads;
|
||||
return this.getMessagesFromPersonIdsService.getMessagesFromObjectRecord(
|
||||
workspaceMember.id,
|
||||
CoreObjectNameSingular.Company,
|
||||
companyId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
}
|
||||
|
||||
@Query(() => TimelineThreadsWithTotalDTO)
|
||||
@Query(() => TimelineThreadsWithTotalDTO, {
|
||||
deprecationReason: 'Use getTimelineThreadsFromObjectRecord instead',
|
||||
})
|
||||
async getTimelineThreadsFromOpportunityId(
|
||||
@AuthUser() user: AuthContextUser,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
@@ -139,16 +189,14 @@ export class TimelineMessagingResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
const timelineThreads =
|
||||
await this.getMessagesFromPersonIdsService.getMessagesFromOpportunityId(
|
||||
workspaceMember.id,
|
||||
opportunityId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
|
||||
return timelineThreads;
|
||||
return this.getMessagesFromPersonIdsService.getMessagesFromObjectRecord(
|
||||
workspaceMember.id,
|
||||
CoreObjectNameSingular.Opportunity,
|
||||
opportunityId,
|
||||
workspace.id,
|
||||
page,
|
||||
pageSize,
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.CONNECTED_ACCOUNTS))
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { RelatedPersonIdsService } from 'src/engine/core-modules/related-person-ids/services/related-person-ids.service';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceCacheModule],
|
||||
providers: [RelatedPersonIdsService],
|
||||
exports: [RelatedPersonIdsService],
|
||||
})
|
||||
export class RelatedPersonIdsModule {}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, type FindOptionsSelect, type FindOptionsWhere } from 'typeorm';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
import {
|
||||
findRelationPathsToPerson,
|
||||
type RelationPathToPerson,
|
||||
} from 'src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util';
|
||||
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 { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
|
||||
const PERSON_OBJECT_NAME_SINGULAR = 'person';
|
||||
|
||||
type RelationWalkRecord = { id: string } & Record<string, unknown>;
|
||||
|
||||
@Injectable()
|
||||
export class RelatedPersonIdsService {
|
||||
constructor(
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {}
|
||||
|
||||
async getRelatedPersonIds({
|
||||
workspaceId,
|
||||
objectNameSingular,
|
||||
recordId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
objectNameSingular: string;
|
||||
recordId: string;
|
||||
}): Promise<string[]> {
|
||||
if (objectNameSingular === PERSON_OBJECT_NAME_SINGULAR) {
|
||||
return [recordId];
|
||||
}
|
||||
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
]);
|
||||
|
||||
const relationPaths = findRelationPathsToPerson({
|
||||
rootObjectNameSingular: objectNameSingular,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
if (relationPaths.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const personIds = new Set<string>();
|
||||
|
||||
for (const relationPath of relationPaths) {
|
||||
const personIdsForPath = await this.walkRelationPath({
|
||||
workspaceId,
|
||||
recordId,
|
||||
relationPath,
|
||||
});
|
||||
|
||||
personIdsForPath.forEach((personId) => personIds.add(personId));
|
||||
}
|
||||
|
||||
return [...personIds];
|
||||
},
|
||||
buildSystemAuthContext(workspaceId),
|
||||
);
|
||||
}
|
||||
|
||||
private async walkRelationPath({
|
||||
workspaceId,
|
||||
recordId,
|
||||
relationPath,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
recordId: string;
|
||||
relationPath: RelationPathToPerson;
|
||||
}): Promise<string[]> {
|
||||
let currentIds = [recordId];
|
||||
|
||||
for (const hop of relationPath) {
|
||||
if (currentIds.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const repository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<RelationWalkRecord>(
|
||||
workspaceId,
|
||||
hop.queryObjectNameSingular,
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
if (hop.direction === RelationType.MANY_TO_ONE) {
|
||||
const records = await repository.find({
|
||||
where: { id: In(currentIds) } as FindOptionsWhere<RelationWalkRecord>,
|
||||
select: {
|
||||
[hop.joinColumnName]: true,
|
||||
} as FindOptionsSelect<RelationWalkRecord>,
|
||||
});
|
||||
|
||||
currentIds = [
|
||||
...new Set(
|
||||
records
|
||||
.map((record) => record[hop.joinColumnName])
|
||||
.filter(
|
||||
(value): value is string =>
|
||||
typeof value === 'string' && isDefined(value),
|
||||
),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
const records = await repository.find({
|
||||
where: {
|
||||
[hop.joinColumnName]: In(currentIds),
|
||||
} as FindOptionsWhere<RelationWalkRecord>,
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
currentIds = [...new Set(records.map((record) => record.id))];
|
||||
}
|
||||
}
|
||||
|
||||
return currentIds;
|
||||
}
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { resolveRelationFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-relation-from-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { findRelationPathsToPerson } from 'src/engine/core-modules/related-person-ids/utils/find-relation-paths-to-person.util';
|
||||
|
||||
jest.mock(
|
||||
'src/engine/metadata-modules/flat-field-metadata/utils/resolve-relation-from-flat-field-metadata.util',
|
||||
);
|
||||
|
||||
const resolveRelationMock = jest.mocked(resolveRelationFromFlatFieldMetadata);
|
||||
|
||||
type RelationSpec = {
|
||||
fieldName: string;
|
||||
relationType: RelationType;
|
||||
targetObjectNameSingular: string;
|
||||
inverseFieldName: string;
|
||||
};
|
||||
|
||||
const buildGraphFixtures = (graph: Record<string, RelationSpec[]>) => {
|
||||
const fieldId = (objectNameSingular: string, fieldName: string) =>
|
||||
`${objectNameSingular}.${fieldName}`;
|
||||
|
||||
const flatObjectMetadataMaps = {
|
||||
byUniversalIdentifier: {},
|
||||
universalIdentifierById: {},
|
||||
} as unknown as FlatEntityMaps<FlatObjectMetadata>;
|
||||
|
||||
const flatFieldMetadataMaps = {
|
||||
byUniversalIdentifier: {},
|
||||
universalIdentifierById: {},
|
||||
} as unknown as FlatEntityMaps<FlatFieldMetadata>;
|
||||
|
||||
const relationSpecByFieldId = new Map<
|
||||
string,
|
||||
{ sourceObjectNameSingular: string; spec: RelationSpec }
|
||||
>();
|
||||
|
||||
for (const [objectNameSingular, relationSpecs] of Object.entries(graph)) {
|
||||
flatObjectMetadataMaps.byUniversalIdentifier[objectNameSingular] = {
|
||||
id: objectNameSingular,
|
||||
nameSingular: objectNameSingular,
|
||||
fieldIds: relationSpecs.map((spec) =>
|
||||
fieldId(objectNameSingular, spec.fieldName),
|
||||
),
|
||||
} as unknown as FlatObjectMetadata;
|
||||
flatObjectMetadataMaps.universalIdentifierById[objectNameSingular] =
|
||||
objectNameSingular;
|
||||
|
||||
for (const spec of relationSpecs) {
|
||||
const id = fieldId(objectNameSingular, spec.fieldName);
|
||||
|
||||
flatFieldMetadataMaps.byUniversalIdentifier[id] = {
|
||||
id,
|
||||
type: 'RELATION',
|
||||
} as unknown as FlatFieldMetadata;
|
||||
flatFieldMetadataMaps.universalIdentifierById[id] = id;
|
||||
|
||||
relationSpecByFieldId.set(id, {
|
||||
sourceObjectNameSingular: objectNameSingular,
|
||||
spec,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
resolveRelationMock.mockImplementation(({ sourceFlatFieldMetadata }) => {
|
||||
const resolved = relationSpecByFieldId.get(sourceFlatFieldMetadata.id);
|
||||
|
||||
if (resolved === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { sourceObjectNameSingular, spec } = resolved;
|
||||
|
||||
return {
|
||||
type: spec.relationType,
|
||||
sourceObjectMetadata: {
|
||||
id: sourceObjectNameSingular,
|
||||
nameSingular: sourceObjectNameSingular,
|
||||
},
|
||||
targetObjectMetadata: {
|
||||
id: spec.targetObjectNameSingular,
|
||||
nameSingular: spec.targetObjectNameSingular,
|
||||
},
|
||||
sourceFieldMetadata: { name: spec.fieldName },
|
||||
targetFieldMetadata: { name: spec.inverseFieldName },
|
||||
} as ReturnType<typeof resolveRelationFromFlatFieldMetadata>;
|
||||
});
|
||||
|
||||
return { flatObjectMetadataMaps, flatFieldMetadataMaps };
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
resolveRelationMock.mockReset();
|
||||
});
|
||||
|
||||
describe('findRelationPathsToPerson', () => {
|
||||
it('returns the empty path for the person object itself', () => {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
buildGraphFixtures({ person: [] });
|
||||
|
||||
expect(
|
||||
findRelationPathsToPerson({
|
||||
rootObjectNameSingular: 'person',
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
).toEqual([[]]);
|
||||
});
|
||||
|
||||
it('resolves a direct relation to person, querying person by its foreign key', () => {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
buildGraphFixtures({
|
||||
company: [
|
||||
{
|
||||
fieldName: 'people',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
targetObjectNameSingular: 'person',
|
||||
inverseFieldName: 'company',
|
||||
},
|
||||
],
|
||||
person: [
|
||||
{
|
||||
fieldName: 'company',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'company',
|
||||
inverseFieldName: 'people',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
findRelationPathsToPerson({
|
||||
rootObjectNameSingular: 'company',
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
).toEqual([
|
||||
[
|
||||
{
|
||||
direction: RelationType.ONE_TO_MANY,
|
||||
queryObjectNameSingular: 'person',
|
||||
joinColumnName: 'companyId',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('resolves person through a two-hop join object', () => {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
buildGraphFixtures({
|
||||
peopleList: [
|
||||
{
|
||||
fieldName: 'peopleListMemberships',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
targetObjectNameSingular: 'peopleListMembership',
|
||||
inverseFieldName: 'peopleList',
|
||||
},
|
||||
],
|
||||
peopleListMembership: [
|
||||
{
|
||||
fieldName: 'peopleList',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'peopleList',
|
||||
inverseFieldName: 'peopleListMemberships',
|
||||
},
|
||||
{
|
||||
fieldName: 'person',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'person',
|
||||
inverseFieldName: 'peopleListMemberships',
|
||||
},
|
||||
],
|
||||
person: [
|
||||
{
|
||||
fieldName: 'peopleListMemberships',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
targetObjectNameSingular: 'peopleListMembership',
|
||||
inverseFieldName: 'person',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(
|
||||
findRelationPathsToPerson({
|
||||
rootObjectNameSingular: 'peopleList',
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
).toEqual([
|
||||
[
|
||||
{
|
||||
direction: RelationType.ONE_TO_MANY,
|
||||
queryObjectNameSingular: 'peopleListMembership',
|
||||
joinColumnName: 'peopleListId',
|
||||
},
|
||||
{
|
||||
direction: RelationType.MANY_TO_ONE,
|
||||
queryObjectNameSingular: 'peopleListMembership',
|
||||
joinColumnName: 'personId',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('collects both a direct and a longer relation chain to person (opportunity)', () => {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
buildGraphFixtures({
|
||||
opportunity: [
|
||||
{
|
||||
fieldName: 'pointOfContact',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'person',
|
||||
inverseFieldName: 'pointOfContactForOpportunities',
|
||||
},
|
||||
{
|
||||
fieldName: 'company',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'company',
|
||||
inverseFieldName: 'opportunities',
|
||||
},
|
||||
],
|
||||
company: [
|
||||
{
|
||||
fieldName: 'people',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
targetObjectNameSingular: 'person',
|
||||
inverseFieldName: 'company',
|
||||
},
|
||||
],
|
||||
person: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
findRelationPathsToPerson({
|
||||
rootObjectNameSingular: 'opportunity',
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
).toEqual([
|
||||
[
|
||||
{
|
||||
direction: RelationType.MANY_TO_ONE,
|
||||
queryObjectNameSingular: 'opportunity',
|
||||
joinColumnName: 'pointOfContactId',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
direction: RelationType.MANY_TO_ONE,
|
||||
queryObjectNameSingular: 'opportunity',
|
||||
joinColumnName: 'companyId',
|
||||
},
|
||||
{
|
||||
direction: RelationType.ONE_TO_MANY,
|
||||
queryObjectNameSingular: 'person',
|
||||
joinColumnName: 'companyId',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns no path when person is unreachable, terminating on relation cycles', () => {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
buildGraphFixtures({
|
||||
rocket: [
|
||||
{
|
||||
fieldName: 'cells',
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
targetObjectNameSingular: 'rocketCell',
|
||||
inverseFieldName: 'rocket',
|
||||
},
|
||||
],
|
||||
rocketCell: [
|
||||
{
|
||||
fieldName: 'rocket',
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
targetObjectNameSingular: 'rocket',
|
||||
inverseFieldName: 'cells',
|
||||
},
|
||||
],
|
||||
person: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
findRelationPathsToPerson({
|
||||
rootObjectNameSingular: 'rocket',
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { resolveRelationFromFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/resolve-relation-from-flat-field-metadata.util';
|
||||
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
|
||||
|
||||
const PERSON_OBJECT_NAME_SINGULAR = 'person';
|
||||
const DEFAULT_MAX_RELATION_DEPTH_TO_PERSON = 3;
|
||||
|
||||
export type RelationHopToPerson = {
|
||||
direction: RelationType;
|
||||
queryObjectNameSingular: string;
|
||||
joinColumnName: string;
|
||||
};
|
||||
|
||||
export type RelationPathToPerson = RelationHopToPerson[];
|
||||
|
||||
export const findRelationPathsToPerson = ({
|
||||
rootObjectNameSingular,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
maxDepth = DEFAULT_MAX_RELATION_DEPTH_TO_PERSON,
|
||||
}: {
|
||||
rootObjectNameSingular: string;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
maxDepth?: number;
|
||||
}): RelationPathToPerson[] => {
|
||||
if (rootObjectNameSingular === PERSON_OBJECT_NAME_SINGULAR) {
|
||||
return [[]];
|
||||
}
|
||||
|
||||
const { idByNameSingular } = buildObjectIdByNameMaps(flatObjectMetadataMaps);
|
||||
const rootObjectId = idByNameSingular[rootObjectNameSingular];
|
||||
|
||||
if (!isDefined(rootObjectId)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let frontier = [{ objectId: rootObjectId, path: [] as RelationPathToPerson }];
|
||||
const visitedObjectIds = new Set<string>([rootObjectId]);
|
||||
const pathsToPerson: RelationPathToPerson[] = [];
|
||||
|
||||
for (let depth = 0; depth < maxDepth; depth++) {
|
||||
const nextFrontier: typeof frontier = [];
|
||||
const objectIdsReachedThisDepth = new Set<string>();
|
||||
|
||||
for (const { objectId, path } of frontier) {
|
||||
const sourceObject = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: objectId,
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(sourceObject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const field of getFlatFieldsFromFlatObjectMetadata(
|
||||
sourceObject,
|
||||
flatFieldMetadataMaps,
|
||||
)) {
|
||||
if (!isFlatFieldMetadataOfType(field, FieldMetadataType.RELATION)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const relation = resolveRelationFromFlatFieldMetadata({
|
||||
sourceFlatFieldMetadata: field,
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(relation)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const joinColumnOwner =
|
||||
relation.type === RelationType.MANY_TO_ONE
|
||||
? {
|
||||
object: relation.sourceObjectMetadata,
|
||||
field: relation.sourceFieldMetadata,
|
||||
}
|
||||
: {
|
||||
object: relation.targetObjectMetadata,
|
||||
field: relation.targetFieldMetadata,
|
||||
};
|
||||
|
||||
const nextPath: RelationPathToPerson = [
|
||||
...path,
|
||||
{
|
||||
direction: relation.type,
|
||||
queryObjectNameSingular: joinColumnOwner.object.nameSingular,
|
||||
joinColumnName: computeMorphOrRelationFieldJoinColumnName({
|
||||
name: joinColumnOwner.field.name,
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
const targetObjectId = relation.targetObjectMetadata.id;
|
||||
|
||||
if (
|
||||
relation.targetObjectMetadata.nameSingular ===
|
||||
PERSON_OBJECT_NAME_SINGULAR
|
||||
) {
|
||||
pathsToPerson.push(nextPath);
|
||||
} else if (!visitedObjectIds.has(targetObjectId)) {
|
||||
objectIdsReachedThisDepth.add(targetObjectId);
|
||||
nextFrontier.push({ objectId: targetObjectId, path: nextPath });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objectIdsReachedThisDepth.forEach((id) => visitedObjectIds.add(id));
|
||||
frontier = nextFrontier;
|
||||
}
|
||||
|
||||
return pathsToPerson;
|
||||
};
|
||||
+396
@@ -0,0 +1,396 @@
|
||||
import gql from 'graphql-tag';
|
||||
import { type DocumentNode } from 'graphql';
|
||||
import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util';
|
||||
import { findManyOperationFactory } from 'test/integration/graphql/utils/find-many-operation-factory.util';
|
||||
import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
|
||||
import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util';
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
const PEOPLE_DISCOVERY_LIMIT = 100;
|
||||
|
||||
const GET_TIMELINE_THREADS = gql`
|
||||
query GetTimelineThreadsFromObjectRecord(
|
||||
$objectNameSingular: String!
|
||||
$recordId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineThreadsFromObjectRecord(
|
||||
objectNameSingular: $objectNameSingular
|
||||
recordId: $recordId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
totalNumberOfThreads
|
||||
timelineThreads {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const GET_TIMELINE_CALENDAR_EVENTS = gql`
|
||||
query GetTimelineCalendarEventsFromObjectRecord(
|
||||
$objectNameSingular: String!
|
||||
$recordId: UUID!
|
||||
$page: Int!
|
||||
$pageSize: Int!
|
||||
) {
|
||||
getTimelineCalendarEventsFromObjectRecord(
|
||||
objectNameSingular: $objectNameSingular
|
||||
recordId: $recordId
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
totalNumberOfCalendarEvents
|
||||
timelineCalendarEvents {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const THREADS_SELECTION = 'totalNumberOfThreads timelineThreads { id }';
|
||||
const CALENDAR_SELECTION =
|
||||
'totalNumberOfCalendarEvents timelineCalendarEvents { id }';
|
||||
|
||||
const buildLegacyQuery = (
|
||||
queryName: string,
|
||||
idArgName: string,
|
||||
selection: string,
|
||||
): DocumentNode =>
|
||||
gql`
|
||||
query ${queryName}($id: UUID!, $page: Int!, $pageSize: Int!) {
|
||||
${queryName}(${idArgName}: $id, page: $page, pageSize: $pageSize) {
|
||||
${selection}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const requestTimeline = (
|
||||
query: DocumentNode,
|
||||
objectNameSingular: string,
|
||||
recordId: string,
|
||||
) =>
|
||||
makeGraphqlAPIRequest({
|
||||
query,
|
||||
variables: { objectNameSingular, recordId, page: 1, pageSize: PAGE_SIZE },
|
||||
});
|
||||
|
||||
const getPeopleWithCompany = async (): Promise<
|
||||
{ id: string; companyId: string }[]
|
||||
> => {
|
||||
const response = await makeGraphqlAPIRequest(
|
||||
findManyOperationFactory({
|
||||
objectMetadataSingularName: 'person',
|
||||
objectMetadataPluralName: 'people',
|
||||
gqlFields: 'id company { id }',
|
||||
first: PEOPLE_DISCOVERY_LIMIT,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
|
||||
return (
|
||||
response.body.data.people.edges
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
.map((edge) => edge.node)
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
.filter((person) => person.company?.id)
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
.map((person) => ({ id: person.id, companyId: person.company.id }))
|
||||
);
|
||||
};
|
||||
|
||||
const findPersonWithThreads = async (
|
||||
people: { id: string; companyId: string }[],
|
||||
) => {
|
||||
for (const person of people) {
|
||||
const response = await requestTimeline(
|
||||
GET_TIMELINE_THREADS,
|
||||
'person',
|
||||
person.id,
|
||||
);
|
||||
|
||||
if (
|
||||
response.body.data.getTimelineThreadsFromObjectRecord
|
||||
.totalNumberOfThreads > 0
|
||||
) {
|
||||
return person;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const findPersonWithCalendarEvents = async (
|
||||
people: { id: string; companyId: string }[],
|
||||
) => {
|
||||
for (const person of people) {
|
||||
const response = await requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
'person',
|
||||
person.id,
|
||||
);
|
||||
|
||||
if (
|
||||
response.body.data.getTimelineCalendarEventsFromObjectRecord
|
||||
.totalNumberOfCalendarEvents > 0
|
||||
) {
|
||||
return person;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
describe('timeline from object record resolvers (integration)', () => {
|
||||
let personWithThreads: { id: string; companyId: string };
|
||||
let personWithEvents: { id: string; companyId: string };
|
||||
|
||||
beforeAll(async () => {
|
||||
const people = await getPeopleWithCompany();
|
||||
|
||||
const threadsSource = await findPersonWithThreads(people);
|
||||
const eventsSource = await findPersonWithCalendarEvents(people);
|
||||
|
||||
if (!threadsSource || !eventsSource) {
|
||||
throw new Error(
|
||||
'Expected the seeded workspace to contain a person with message threads and calendar events',
|
||||
);
|
||||
}
|
||||
|
||||
personWithThreads = threadsSource;
|
||||
personWithEvents = eventsSource;
|
||||
});
|
||||
|
||||
it('should derive a company message timeline from its related people', async () => {
|
||||
const [personResponse, companyResponse] = await Promise.all([
|
||||
requestTimeline(GET_TIMELINE_THREADS, 'person', personWithThreads.id),
|
||||
requestTimeline(
|
||||
GET_TIMELINE_THREADS,
|
||||
'company',
|
||||
personWithThreads.companyId,
|
||||
),
|
||||
]);
|
||||
|
||||
expect(personResponse.body.errors).toBeUndefined();
|
||||
expect(companyResponse.body.errors).toBeUndefined();
|
||||
|
||||
const personThreadCount =
|
||||
personResponse.body.data.getTimelineThreadsFromObjectRecord
|
||||
.totalNumberOfThreads;
|
||||
const companyThreadCount =
|
||||
companyResponse.body.data.getTimelineThreadsFromObjectRecord
|
||||
.totalNumberOfThreads;
|
||||
|
||||
expect(personThreadCount).toBeGreaterThan(0);
|
||||
expect(companyThreadCount).toBeGreaterThanOrEqual(personThreadCount);
|
||||
});
|
||||
|
||||
it('should derive a company calendar timeline from its related people', async () => {
|
||||
const [personResponse, companyResponse] = await Promise.all([
|
||||
requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
'person',
|
||||
personWithEvents.id,
|
||||
),
|
||||
requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
'company',
|
||||
personWithEvents.companyId,
|
||||
),
|
||||
]);
|
||||
|
||||
expect(personResponse.body.errors).toBeUndefined();
|
||||
expect(companyResponse.body.errors).toBeUndefined();
|
||||
|
||||
const personEventCount =
|
||||
personResponse.body.data.getTimelineCalendarEventsFromObjectRecord
|
||||
.totalNumberOfCalendarEvents;
|
||||
const companyEventCount =
|
||||
companyResponse.body.data.getTimelineCalendarEventsFromObjectRecord
|
||||
.totalNumberOfCalendarEvents;
|
||||
|
||||
expect(personEventCount).toBeGreaterThan(0);
|
||||
expect(companyEventCount).toBeGreaterThanOrEqual(personEventCount);
|
||||
});
|
||||
|
||||
it('should serve getTimelineThreadsFromPersonId identically to the object-record resolver', async () => {
|
||||
const [fromObjectRecord, fromLegacy] = await Promise.all([
|
||||
requestTimeline(GET_TIMELINE_THREADS, 'person', personWithThreads.id),
|
||||
makeGraphqlAPIRequest({
|
||||
query: buildLegacyQuery(
|
||||
'getTimelineThreadsFromPersonId',
|
||||
'personId',
|
||||
THREADS_SELECTION,
|
||||
),
|
||||
variables: { id: personWithThreads.id, page: 1, pageSize: PAGE_SIZE },
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(fromLegacy.body.errors).toBeUndefined();
|
||||
expect(fromLegacy.body.data.getTimelineThreadsFromPersonId).toEqual(
|
||||
fromObjectRecord.body.data.getTimelineThreadsFromObjectRecord,
|
||||
);
|
||||
});
|
||||
|
||||
it('should serve getTimelineThreadsFromCompanyId identically to the object-record resolver', async () => {
|
||||
const [fromObjectRecord, fromLegacy] = await Promise.all([
|
||||
requestTimeline(
|
||||
GET_TIMELINE_THREADS,
|
||||
'company',
|
||||
personWithThreads.companyId,
|
||||
),
|
||||
makeGraphqlAPIRequest({
|
||||
query: buildLegacyQuery(
|
||||
'getTimelineThreadsFromCompanyId',
|
||||
'companyId',
|
||||
THREADS_SELECTION,
|
||||
),
|
||||
variables: {
|
||||
id: personWithThreads.companyId,
|
||||
page: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(fromLegacy.body.errors).toBeUndefined();
|
||||
expect(fromLegacy.body.data.getTimelineThreadsFromCompanyId).toEqual(
|
||||
fromObjectRecord.body.data.getTimelineThreadsFromObjectRecord,
|
||||
);
|
||||
});
|
||||
|
||||
it('should serve getTimelineCalendarEventsFromPersonId identically to the object-record resolver', async () => {
|
||||
const [fromObjectRecord, fromLegacy] = await Promise.all([
|
||||
requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
'person',
|
||||
personWithEvents.id,
|
||||
),
|
||||
makeGraphqlAPIRequest({
|
||||
query: buildLegacyQuery(
|
||||
'getTimelineCalendarEventsFromPersonId',
|
||||
'personId',
|
||||
CALENDAR_SELECTION,
|
||||
),
|
||||
variables: { id: personWithEvents.id, page: 1, pageSize: PAGE_SIZE },
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(fromLegacy.body.errors).toBeUndefined();
|
||||
expect(fromLegacy.body.data.getTimelineCalendarEventsFromPersonId).toEqual(
|
||||
fromObjectRecord.body.data.getTimelineCalendarEventsFromObjectRecord,
|
||||
);
|
||||
});
|
||||
|
||||
it('should serve getTimelineCalendarEventsFromCompanyId identically to the object-record resolver', async () => {
|
||||
const [fromObjectRecord, fromLegacy] = await Promise.all([
|
||||
requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
'company',
|
||||
personWithEvents.companyId,
|
||||
),
|
||||
makeGraphqlAPIRequest({
|
||||
query: buildLegacyQuery(
|
||||
'getTimelineCalendarEventsFromCompanyId',
|
||||
'companyId',
|
||||
CALENDAR_SELECTION,
|
||||
),
|
||||
variables: {
|
||||
id: personWithEvents.companyId,
|
||||
page: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(fromLegacy.body.errors).toBeUndefined();
|
||||
expect(fromLegacy.body.data.getTimelineCalendarEventsFromCompanyId).toEqual(
|
||||
fromObjectRecord.body.data.getTimelineCalendarEventsFromObjectRecord,
|
||||
);
|
||||
});
|
||||
|
||||
describe('with a custom object that has no people on its timeline', () => {
|
||||
const CUSTOM_OBJECT_NAME_SINGULAR = 'timelineProbe';
|
||||
const CUSTOM_RECORD_ID = '20202020-cccc-4000-8000-0000000000a1';
|
||||
|
||||
let customObjectMetadataId: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
const { data } = await createOneObjectMetadata({
|
||||
input: {
|
||||
nameSingular: CUSTOM_OBJECT_NAME_SINGULAR,
|
||||
namePlural: 'timelineProbes',
|
||||
labelSingular: 'Timeline Probe',
|
||||
labelPlural: 'Timeline Probes',
|
||||
icon: 'IconRadar',
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
customObjectMetadataId = data.createOneObject.id;
|
||||
|
||||
await makeGraphqlAPIRequest(
|
||||
createOneOperationFactory({
|
||||
objectMetadataSingularName: CUSTOM_OBJECT_NAME_SINGULAR,
|
||||
gqlFields: 'id',
|
||||
data: { id: CUSTOM_RECORD_ID, name: 'Probe' },
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await updateOneObjectMetadata({
|
||||
input: {
|
||||
idToUpdate: customObjectMetadataId,
|
||||
updatePayload: { isActive: false },
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
await deleteOneObjectMetadata({
|
||||
input: { idToDelete: customObjectMetadataId },
|
||||
expectToFail: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an empty message timeline instead of crashing', async () => {
|
||||
const response = await requestTimeline(
|
||||
GET_TIMELINE_THREADS,
|
||||
CUSTOM_OBJECT_NAME_SINGULAR,
|
||||
CUSTOM_RECORD_ID,
|
||||
);
|
||||
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
expect(
|
||||
response.body.data.getTimelineThreadsFromObjectRecord
|
||||
.totalNumberOfThreads,
|
||||
).toBe(0);
|
||||
expect(
|
||||
response.body.data.getTimelineThreadsFromObjectRecord.timelineThreads,
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return an empty calendar timeline instead of crashing', async () => {
|
||||
const response = await requestTimeline(
|
||||
GET_TIMELINE_CALENDAR_EVENTS,
|
||||
CUSTOM_OBJECT_NAME_SINGULAR,
|
||||
CUSTOM_RECORD_ID,
|
||||
);
|
||||
|
||||
expect(response.body.errors).toBeUndefined();
|
||||
expect(
|
||||
response.body.data.getTimelineCalendarEventsFromObjectRecord
|
||||
.totalNumberOfCalendarEvents,
|
||||
).toBe(0);
|
||||
expect(
|
||||
response.body.data.getTimelineCalendarEventsFromObjectRecord
|
||||
.timelineCalendarEvents,
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user