diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 9dd6338670..97ebd9b4d6 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -118,6 +118,40 @@ export type AgentChatThread = { updatedAt: Scalars['DateTime']; }; +export type AgentChatThreadConnection = { + __typename?: 'AgentChatThreadConnection'; + /** Array of edges. */ + edges: Array; + /** Paging information */ + pageInfo: PageInfo; +}; + +export type AgentChatThreadEdge = { + __typename?: 'AgentChatThreadEdge'; + /** Cursor for this node. */ + cursor: Scalars['ConnectionCursor']; + /** The node containing the AgentChatThread */ + node: AgentChatThread; +}; + +export type AgentChatThreadFilter = { + and?: InputMaybe>; + id?: InputMaybe; + or?: InputMaybe>; + updatedAt?: InputMaybe; +}; + +export type AgentChatThreadSort = { + direction: SortDirection; + field: AgentChatThreadSortFields; + nulls?: InputMaybe; +}; + +export enum AgentChatThreadSortFields { + id = 'id', + updatedAt = 'updatedAt' +} + export type AgentIdInput = { /** The id of the agent. */ id: Scalars['UUID']; @@ -1320,6 +1354,26 @@ export enum DatabaseEventAction { UPSERTED = 'UPSERTED' } +export type DateFieldComparison = { + between?: InputMaybe; + eq?: InputMaybe; + gt?: InputMaybe; + gte?: InputMaybe; + in?: InputMaybe>; + is?: InputMaybe; + isNot?: InputMaybe; + lt?: InputMaybe; + lte?: InputMaybe; + neq?: InputMaybe; + notBetween?: InputMaybe; + notIn?: InputMaybe>; +}; + +export type DateFieldComparisonBetween = { + lower: Scalars['DateTime']; + upper: Scalars['DateTime']; +}; + export type DeleteApprovedAccessDomainInput = { id: Scalars['UUID']; }; @@ -3868,7 +3922,7 @@ export type Query = { billingPortalSession: BillingSession; chatMessages: Array; chatThread: AgentChatThread; - chatThreads: Array; + chatThreads: AgentChatThreadConnection; checkUserExists: CheckUserExist; checkWorkspaceInviteHashIsValid: WorkspaceInviteHashValid; commandMenuItem?: Maybe; @@ -3987,6 +4041,13 @@ export type QueryChatThreadArgs = { }; +export type QueryChatThreadsArgs = { + filter?: AgentChatThreadFilter; + paging?: CursorPaging; + sorting?: Array; +}; + + export type QueryCheckUserExistsArgs = { captchaToken?: InputMaybe; email: Scalars['String']; @@ -4594,6 +4655,18 @@ export type Skill = { updatedAt: Scalars['DateTime']; }; +/** Sort Directions */ +export enum SortDirection { + ASC = 'ASC', + DESC = 'DESC' +} + +/** Sort Nulls Options */ +export enum SortNulls { + NULLS_FIRST = 'NULLS_FIRST', + NULLS_LAST = 'NULLS_LAST' +} + export type StandaloneRichTextConfiguration = { __typename?: 'StandaloneRichTextConfiguration'; body: RichTextV2Body; @@ -5690,10 +5763,12 @@ export type GetChatMessagesQueryVariables = Exact<{ export type GetChatMessagesQuery = { __typename?: 'Query', chatMessages: Array<{ __typename?: 'AgentMessage', id: string, threadId: string, turnId: string, role: string, createdAt: string, parts: Array<{ __typename?: 'AgentMessagePart', id: string, messageId: string, orderIndex: number, type: string, textContent?: string | null, reasoningContent?: string | null, toolName?: string | null, toolCallId?: string | null, toolInput?: any | null, toolOutput?: any | null, state?: string | null, errorMessage?: string | null, errorDetails?: any | null, sourceUrlSourceId?: string | null, sourceUrlUrl?: string | null, sourceUrlTitle?: string | null, sourceDocumentSourceId?: string | null, sourceDocumentMediaType?: string | null, sourceDocumentTitle?: string | null, sourceDocumentFilename?: string | null, fileMediaType?: string | null, fileFilename?: string | null, fileUrl?: string | null, providerMetadata?: any | null, createdAt: string }> }> }; -export type GetChatThreadsQueryVariables = Exact<{ [key: string]: never; }>; +export type GetChatThreadsQueryVariables = Exact<{ + paging?: InputMaybe; +}>; -export type GetChatThreadsQuery = { __typename?: 'Query', chatThreads: Array<{ __typename?: 'AgentChatThread', id: string, title?: string | null, totalInputTokens: number, totalOutputTokens: number, contextWindowTokens?: number | null, conversationSize: number, totalInputCredits: number, totalOutputCredits: number, createdAt: string, updatedAt: string }> }; +export type GetChatThreadsQuery = { __typename?: 'Query', chatThreads: { __typename?: 'AgentChatThreadConnection', edges: Array<{ __typename?: 'AgentChatThreadEdge', cursor: any, node: { __typename?: 'AgentChatThread', id: string, title?: string | null, totalInputTokens: number, totalOutputTokens: number, contextWindowTokens?: number | null, conversationSize: number, totalInputCredits: number, totalOutputCredits: number, createdAt: string, updatedAt: string } }>, pageInfo: { __typename?: 'PageInfo', endCursor?: any | null, hasNextPage?: boolean | null } } }; export type GetToolIndexQueryVariables = Exact<{ [key: string]: never; }>; @@ -9048,18 +9123,27 @@ export type GetChatMessagesQueryHookResult = ReturnType; export type GetChatMessagesQueryResult = Apollo.QueryResult; export const GetChatThreadsDocument = gql` - query GetChatThreads { - chatThreads { - id - title - totalInputTokens - totalOutputTokens - contextWindowTokens - conversationSize - totalInputCredits - totalOutputCredits - createdAt - updatedAt + query GetChatThreads($paging: CursorPaging) { + chatThreads(paging: $paging) { + edges { + node { + id + title + totalInputTokens + totalOutputTokens + contextWindowTokens + conversationSize + totalInputCredits + totalOutputCredits + createdAt + updatedAt + } + cursor + } + pageInfo { + endCursor + hasNextPage + } } } `; @@ -9076,6 +9160,7 @@ export const GetChatThreadsDocument = gql` * @example * const { data, loading, error } = useGetChatThreadsQuery({ * variables: { + * paging: // value for 'paging' * }, * }); */ diff --git a/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx b/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx index 95f6e90e9c..f2a5ef8f0e 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatTab.tsx @@ -107,7 +107,7 @@ const StyledScrollWrapper = styled(ScrollWrapper)` gap: ${themeCssVariables.spacing[2]}; overflow-y: auto; padding: ${themeCssVariables.spacing[3]}; - width: calc(100% - 24px); + width: calc(100% - 24px) !important; `; const StyledButtonsContainer = styled.div` diff --git a/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx b/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx index 26848572a3..091686a0bf 100644 --- a/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx +++ b/packages/twenty-front/src/modules/ai/components/AIChatThreadsList.tsx @@ -3,6 +3,7 @@ import { styled } from '@linaria/react'; import { AIChatThreadGroup } from '@/ai/components/AIChatThreadGroup'; import { AIChatThreadsListEffect } from '@/ai/components/AIChatThreadsListEffect'; import { AIChatSkeletonLoader } from '@/ai/components/internal/AIChatSkeletonLoader'; +import { useChatThreads } from '@/ai/hooks/useChatThreads'; import { useCreateNewAIChatThread } from '@/ai/hooks/useCreateNewAIChatThread'; import { groupThreadsByDate } from '@/ai/utils/groupThreadsByDate'; import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement'; @@ -12,7 +13,6 @@ import { capitalize } from 'twenty-shared/utils'; import { Button } from 'twenty-ui/input'; import { themeCssVariables } from 'twenty-ui/theme-constants'; import { getOsControlSymbol } from 'twenty-ui/utilities'; -import { useGetChatThreadsQuery } from '~/generated-metadata/graphql'; const StyledContainer = styled.div` background: ${themeCssVariables.background.secondary}; @@ -47,11 +47,11 @@ export const AIChatThreadsList = () => { dependencies: [createChatThread], }); - const { data: { chatThreads = [] } = {}, loading } = useGetChatThreadsQuery(); + const { threads, hasNextPage, loading, fetchMoreRef } = useChatThreads(); - const groupedThreads = groupThreadsByDate(chatThreads); + const groupedThreads = groupThreadsByDate(threads); - if (loading === true) { + if (loading && threads.length === 0) { return ; } @@ -60,13 +60,16 @@ export const AIChatThreadsList = () => { - {Object.entries(groupedThreads).map(([title, threads]) => ( + {Object.entries(groupedThreads).map(([title, threadsInGroup]) => ( ))} + {hasNextPage ? ( +
+ ) : null}