3675 inbox count is wrong in emailthreads (#3677)
* add type * query total number of threads * graphql data generate * wip * wip * Fix fetch more * fix --------- Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
@ -60,4 +60,4 @@
|
||||
"msw": {
|
||||
"workerDirectory": "public"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,8 +378,8 @@ export type Query = {
|
||||
currentUser: User;
|
||||
currentWorkspace: Workspace;
|
||||
findWorkspaceFromInviteHash: Workspace;
|
||||
getTimelineThreadsFromCompanyId: Array<TimelineThread>;
|
||||
getTimelineThreadsFromPersonId: Array<TimelineThread>;
|
||||
getTimelineThreadsFromCompanyId: TimelineThreadsWithTotal;
|
||||
getTimelineThreadsFromPersonId: TimelineThreadsWithTotal;
|
||||
object: Object;
|
||||
objects: ObjectConnection;
|
||||
validatePasswordResetToken: ValidatePasswordResetToken;
|
||||
@ -517,6 +517,12 @@ export type TimelineThreadParticipant = {
|
||||
workspaceMemberId?: Maybe<Scalars['ID']>;
|
||||
};
|
||||
|
||||
export type TimelineThreadsWithTotal = {
|
||||
__typename?: 'TimelineThreadsWithTotal';
|
||||
timelineThreads: Array<TimelineThread>;
|
||||
totalNumberOfThreads: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type TransientToken = {
|
||||
__typename?: 'TransientToken';
|
||||
transientToken: AuthToken;
|
||||
@ -715,6 +721,8 @@ export type ParticipantFragmentFragment = { __typename?: 'TimelineThreadParticip
|
||||
|
||||
export type TimelineThreadFragmentFragment = { __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> };
|
||||
|
||||
export type TimelineThreadsWithTotalFragmentFragment = { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> };
|
||||
|
||||
export type GetTimelineThreadsFromCompanyIdQueryVariables = Exact<{
|
||||
companyId: Scalars['ID'];
|
||||
page: Scalars['Int'];
|
||||
@ -722,7 +730,7 @@ export type GetTimelineThreadsFromCompanyIdQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineThreadsFromCompanyIdQuery = { __typename?: 'Query', getTimelineThreadsFromCompanyId: Array<{ __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> };
|
||||
export type GetTimelineThreadsFromCompanyIdQuery = { __typename?: 'Query', getTimelineThreadsFromCompanyId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
|
||||
export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
|
||||
personId: Scalars['ID'];
|
||||
@ -731,7 +739,7 @@ export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: Array<{ __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> };
|
||||
export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: string, read: boolean, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: string | null, workspaceMemberId?: string | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } };
|
||||
|
||||
export type CreateEventMutationVariables = Exact<{
|
||||
type: Scalars['String'];
|
||||
@ -912,6 +920,14 @@ export const TimelineThreadFragmentFragmentDoc = gql`
|
||||
participantCount
|
||||
}
|
||||
${ParticipantFragmentFragmentDoc}`;
|
||||
export const TimelineThreadsWithTotalFragmentFragmentDoc = gql`
|
||||
fragment TimelineThreadsWithTotalFragment on TimelineThreadsWithTotal {
|
||||
totalNumberOfThreads
|
||||
timelineThreads {
|
||||
...TimelineThreadFragment
|
||||
}
|
||||
}
|
||||
${TimelineThreadFragmentFragmentDoc}`;
|
||||
export const AuthTokenFragmentFragmentDoc = gql`
|
||||
fragment AuthTokenFragment on AuthToken {
|
||||
token
|
||||
@ -970,10 +986,10 @@ export const GetTimelineThreadsFromCompanyIdDocument = gql`
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadFragment
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${TimelineThreadFragmentFragmentDoc}`;
|
||||
${TimelineThreadsWithTotalFragmentFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useGetTimelineThreadsFromCompanyIdQuery__
|
||||
@ -1011,10 +1027,10 @@ export const GetTimelineThreadsFromPersonIdDocument = gql`
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadFragment
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${TimelineThreadFragmentFragmentDoc}`;
|
||||
${TimelineThreadsWithTotalFragmentFragmentDoc}`;
|
||||
|
||||
/**
|
||||
* __useGetTimelineThreadsFromPersonIdQuery__
|
||||
|
||||
@ -25,6 +25,7 @@ import { FetchMoreLoader } from '@/ui/utilities/loading-state/components/FetchMo
|
||||
import {
|
||||
GetTimelineThreadsFromPersonIdQueryVariables,
|
||||
TimelineThread,
|
||||
TimelineThreadsWithTotal,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -85,7 +86,7 @@ export const EmailThreads = ({
|
||||
page: emailThreadsPage.pageNumber + 1,
|
||||
},
|
||||
updateQuery: (prev, { fetchMoreResult }) => {
|
||||
if (!fetchMoreResult || !fetchMoreResult?.[queryName].length) {
|
||||
if (!fetchMoreResult?.[queryName]?.timelineThreads?.length) {
|
||||
setEmailThreadsPage((emailThreadsPage) => ({
|
||||
...emailThreadsPage,
|
||||
hasNextPage: false,
|
||||
@ -94,10 +95,13 @@ export const EmailThreads = ({
|
||||
}
|
||||
|
||||
return {
|
||||
[queryName]: [
|
||||
...(prev?.[queryName] ?? []),
|
||||
...(fetchMoreResult?.[queryName] ?? []),
|
||||
],
|
||||
[queryName]: {
|
||||
...prev?.[queryName],
|
||||
timelineThreads: [
|
||||
...(prev?.[queryName]?.timelineThreads ?? []),
|
||||
...(fetchMoreResult?.[queryName]?.timelineThreads ?? []),
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@ -115,11 +119,8 @@ export const EmailThreads = ({
|
||||
});
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timelineThreads: TimelineThread[] = data?.[queryName] ?? [];
|
||||
const { totalNumberOfThreads, timelineThreads }: TimelineThreadsWithTotal =
|
||||
data?.[queryName] ?? [];
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
@ -128,21 +129,23 @@ export const EmailThreads = ({
|
||||
title={
|
||||
<>
|
||||
Inbox{' '}
|
||||
<StyledEmailCount>{timelineThreads?.length}</StyledEmailCount>
|
||||
<StyledEmailCount>{totalNumberOfThreads ?? 0}</StyledEmailCount>
|
||||
</>
|
||||
}
|
||||
fontColor={H1TitleFontColor.Primary}
|
||||
/>
|
||||
<Card>
|
||||
{timelineThreads.map((thread: TimelineThread, index: number) => (
|
||||
<EmailThreadPreview
|
||||
key={index}
|
||||
divider={index < timelineThreads.length - 1}
|
||||
thread={thread}
|
||||
onClick={() => openEmailThread(thread)}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
{!loading && (
|
||||
<Card>
|
||||
{timelineThreads?.map((thread: TimelineThread, index: number) => (
|
||||
<EmailThreadPreview
|
||||
key={index}
|
||||
divider={index < timelineThreads.length - 1}
|
||||
thread={thread}
|
||||
onClick={() => openEmailThread(thread)}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
)}
|
||||
<FetchMoreLoader
|
||||
loading={isFetchingMoreEmails}
|
||||
onLastRowVisible={fetchMoreRecords}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineThreadFragment } from '@/activities/emails/queries/fragments/timelineThreadFragment';
|
||||
|
||||
export const timelineThreadWithTotalFragment = gql`
|
||||
fragment TimelineThreadsWithTotalFragment on TimelineThreadsWithTotal {
|
||||
totalNumberOfThreads
|
||||
timelineThreads {
|
||||
...TimelineThreadFragment
|
||||
}
|
||||
}
|
||||
${timelineThreadFragment}
|
||||
`;
|
||||
@ -1,6 +1,6 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineThreadFragment } from '@/activities/emails/queries/fragments/timelineThreadFragment';
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/queries/fragments/timelineThreadWithTotalFragment';
|
||||
|
||||
export const getTimelineThreadsFromCompanyId = gql`
|
||||
query GetTimelineThreadsFromCompanyId(
|
||||
@ -13,8 +13,8 @@ export const getTimelineThreadsFromCompanyId = gql`
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadFragment
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineThreadFragment}
|
||||
${timelineThreadWithTotalFragment}
|
||||
`;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
import { timelineThreadFragment } from '@/activities/emails/queries/fragments/timelineThreadFragment';
|
||||
import { timelineThreadWithTotalFragment } from '@/activities/emails/queries/fragments/timelineThreadWithTotalFragment';
|
||||
|
||||
export const getTimelineThreadsFromPersonId = gql`
|
||||
query GetTimelineThreadsFromPersonId(
|
||||
@ -13,8 +13,8 @@ export const getTimelineThreadsFromPersonId = gql`
|
||||
page: $page
|
||||
pageSize: $pageSize
|
||||
) {
|
||||
...TimelineThreadFragment
|
||||
...TimelineThreadsWithTotalFragment
|
||||
}
|
||||
}
|
||||
${timelineThreadFragment}
|
||||
${timelineThreadWithTotalFragment}
|
||||
`;
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
import { Field, Int, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { TimelineThread } from 'src/core/messaging/dtos/timeline-thread.dto';
|
||||
|
||||
@ObjectType('TimelineThreadsWithTotal')
|
||||
export class TimelineThreadsWithTotal {
|
||||
@Field(() => Int)
|
||||
totalNumberOfThreads: number;
|
||||
|
||||
@Field(() => [TimelineThread])
|
||||
timelineThreads: TimelineThread[];
|
||||
}
|
||||
@ -15,8 +15,8 @@ import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
||||
import { Workspace } from 'src/core/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||
import { TimelineMessagingService } from 'src/core/messaging/timeline-messaging.service';
|
||||
import { TimelineThread } from 'src/core/messaging/dtos/timeline-thread.dto';
|
||||
import { TIMELINE_THREADS_MAX_PAGE_SIZE } from 'src/core/messaging/constants/messaging.constants';
|
||||
import { TimelineThreadsWithTotal } from 'src/core/messaging/dtos/timeline-threads-with-total.dto';
|
||||
|
||||
@ArgsType()
|
||||
class GetTimelineThreadsFromPersonIdArgs {
|
||||
@ -45,13 +45,13 @@ class GetTimelineThreadsFromCompanyIdArgs {
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => [TimelineThread])
|
||||
@Resolver(() => TimelineThreadsWithTotal)
|
||||
export class TimelineMessagingResolver {
|
||||
constructor(
|
||||
private readonly timelineMessagingService: TimelineMessagingService,
|
||||
) {}
|
||||
|
||||
@Query(() => [TimelineThread])
|
||||
@Query(() => TimelineThreadsWithTotal)
|
||||
async getTimelineThreadsFromPersonId(
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
@Args() { personId, page, pageSize }: GetTimelineThreadsFromPersonIdArgs,
|
||||
@ -67,7 +67,7 @@ export class TimelineMessagingResolver {
|
||||
return timelineThreads;
|
||||
}
|
||||
|
||||
@Query(() => [TimelineThread])
|
||||
@Query(() => TimelineThreadsWithTotal)
|
||||
async getTimelineThreadsFromCompanyId(
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
@Args() { companyId, page, pageSize }: GetTimelineThreadsFromCompanyIdArgs,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { TIMELINE_THREADS_DEFAULT_PAGE_SIZE } from 'src/core/messaging/constants/messaging.constants';
|
||||
import { TimelineThread } from 'src/core/messaging/dtos/timeline-thread.dto';
|
||||
import { TimelineThreadsWithTotal } from 'src/core/messaging/dtos/timeline-threads-with-total.dto';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { DataSourceService } from 'src/metadata/data-source/data-source.service';
|
||||
|
||||
@ -27,7 +27,7 @@ export class TimelineMessagingService {
|
||||
personIds: string[],
|
||||
page: number = 1,
|
||||
pageSize: number = TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
|
||||
): Promise<TimelineThread[]> {
|
||||
): Promise<TimelineThreadsWithTotal> {
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
const dataSourceMetadata =
|
||||
@ -82,7 +82,10 @@ export class TimelineMessagingService {
|
||||
);
|
||||
|
||||
if (!messageThreads) {
|
||||
return [];
|
||||
return {
|
||||
totalNumberOfThreads: 0,
|
||||
timelineThreads: [],
|
||||
};
|
||||
}
|
||||
|
||||
const messageThreadIds = messageThreads.map(
|
||||
@ -239,6 +242,23 @@ export class TimelineMessagingService {
|
||||
[messageThreadIds],
|
||||
);
|
||||
|
||||
const totalNumberOfThreads = await workspaceDataSource?.query(
|
||||
`
|
||||
SELECT COUNT(DISTINCT "messageThread".id)
|
||||
FROM
|
||||
${dataSourceMetadata.schema}."message" message
|
||||
LEFT JOIN
|
||||
${dataSourceMetadata.schema}."messageThread" "messageThread" ON "messageThread".id = message."messageThreadId"
|
||||
LEFT JOIN
|
||||
${dataSourceMetadata.schema}."messageParticipant" "messageParticipant" ON "messageParticipant"."messageId" = message.id
|
||||
LEFT JOIN
|
||||
${dataSourceMetadata.schema}."person" person ON person.id = "messageParticipant"."personId"
|
||||
WHERE
|
||||
person.id = ANY($1)
|
||||
`,
|
||||
[personIds],
|
||||
);
|
||||
|
||||
const threadParticipantsByThreadId: {
|
||||
[key: string]: TimelineThreadParticipant[];
|
||||
} = messageThreadIds.reduce((messageThreadIdAcc, messageThreadId) => {
|
||||
@ -350,7 +370,10 @@ export class TimelineMessagingService {
|
||||
};
|
||||
});
|
||||
|
||||
return timelineThreads;
|
||||
return {
|
||||
totalNumberOfThreads: totalNumberOfThreads[0]?.count ?? 0,
|
||||
timelineThreads,
|
||||
};
|
||||
}
|
||||
|
||||
async getMessagesFromCompanyId(
|
||||
@ -358,7 +381,7 @@ export class TimelineMessagingService {
|
||||
companyId: string,
|
||||
page: number = 1,
|
||||
pageSize: number = TIMELINE_THREADS_DEFAULT_PAGE_SIZE,
|
||||
) {
|
||||
): Promise<TimelineThreadsWithTotal> {
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
workspaceId,
|
||||
@ -380,7 +403,10 @@ export class TimelineMessagingService {
|
||||
);
|
||||
|
||||
if (!personIds) {
|
||||
return [];
|
||||
return {
|
||||
totalNumberOfThreads: 0,
|
||||
timelineThreads: [],
|
||||
};
|
||||
}
|
||||
|
||||
const formattedPersonIds = personIds.map(
|
||||
|
||||
Reference in New Issue
Block a user