Skip to content

Commit c3e807e

Browse files
Merge pull request #282 from microsoft/fetch-history-US
fix: fetch history on button click and not on web page load
2 parents a994fe3 + a5d30cb commit c3e807e

File tree

13 files changed

+156
-103
lines changed

13 files changed

+156
-103
lines changed

frontend/src/api/api.ts

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -50,44 +50,40 @@ export const fetchChatHistoryInit = (): Conversation[] | null => {
5050
}
5151

5252
export const historyList = async (offset = 0): Promise<Conversation[] | null> => {
53-
const response = await fetch(`/history/list?offset=${offset}`, {
54-
method: 'GET'
55-
})
56-
.then(async res => {
57-
const payload = await res.json()
58-
if (!Array.isArray(payload)) {
59-
console.error('There was an issue fetching your data.')
60-
return null
61-
}
62-
const conversations: Conversation[] = await Promise.all(
63-
payload.map(async (conv: any) => {
64-
let convMessages: ChatMessage[] = []
65-
convMessages = await historyRead(conv.id)
66-
.then(res => {
67-
return res
68-
})
69-
.catch(err => {
70-
console.error('error fetching messages: ', err)
71-
return []
72-
})
73-
const conversation: Conversation = {
74-
id: conv.id,
75-
title: conv.title,
76-
date: conv.createdAt,
77-
messages: convMessages
78-
}
79-
return conversation
80-
})
81-
)
82-
return conversations
83-
})
84-
.catch(_err => {
85-
console.error('There was an issue fetching your data.')
86-
return null
87-
})
53+
try {
54+
const res = await fetch(`/history/list?offset=${offset}`, { method: 'GET' });
55+
const payload = await res.json();
8856

89-
return response
90-
}
57+
if (!Array.isArray(payload)) {
58+
console.error('There was an issue fetching your data.');
59+
return null;
60+
}
61+
62+
const conversations: Conversation[] = await Promise.all(
63+
payload.map(async (conv: any) => {
64+
let convMessages: ChatMessage[] = [];
65+
66+
// try {
67+
// convMessages = await historyRead(conv.id);
68+
// } catch (err) {
69+
// console.error('Error fetching messages:', err);
70+
// }
71+
72+
return {
73+
id: conv.id,
74+
title: conv.title,
75+
date: conv.createdAt,
76+
messages: convMessages,
77+
};
78+
})
79+
);
80+
81+
return conversations;
82+
} catch (err) {
83+
console.error('There was an issue fetching your data.', err);
84+
return null;
85+
}
86+
};
9187

9288
export const historyRead = async (convId: string): Promise<ChatMessage[]> => {
9389
const response = await fetch('/history/read', {

frontend/src/components/ChatHistory/ChatHistoryList.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ const mockState = {
2626
isGenerating: false,
2727
isRequestInitiated: false,
2828
failedSections : [],
29-
isFailedReqInitiated : false
29+
isFailedReqInitiated : false,
30+
isLoading : false,
3031
};
3132

3233
const renderChatHistoryList = (stateOverride = {}) => {

frontend/src/components/ChatHistory/ChatHistoryListItem.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from '@fluentui/react'
1919
import { useBoolean } from '@fluentui/react-hooks'
2020

21-
import { historyDelete, historyList, historyRename } from '../../api'
21+
import { historyDelete, historyList, historyRead, historyRename } from '../../api'
2222
import { Conversation } from '../../api/models'
2323
import { AppStateContext } from '../../state/AppProvider'
2424

@@ -121,9 +121,28 @@ export const ChatHistoryListItemCell: React.FC<ChatHistoryListItemCellProps> = (
121121
setEditTitle(item?.title)
122122
}
123123

124-
const handleSelectItem = () => {
125-
onSelect(item)
126-
appStateContext?.dispatch({ type: 'UPDATE_CURRENT_CHAT', payload: item })
124+
const handleSelectItem = async () => {
125+
if (!item) return;
126+
127+
appStateContext?.dispatch({ type: 'SET_LOADING', payload: true });
128+
try {
129+
// Fetch messages for the selected chat
130+
const messages = await historyRead(item.id);
131+
132+
// Update the global state with the selected chat and its messages
133+
appStateContext?.dispatch({
134+
type: 'UPDATE_CURRENT_CHAT',
135+
payload: { ...item, messages }
136+
});
137+
138+
// Call the onSelect function with updated chat data
139+
onSelect({ ...item, messages });
140+
} catch (error) {
141+
console.error('Error fetching messages:', error);
142+
} finally {
143+
// Stop loading after messages are fetched
144+
appStateContext?.dispatch({ type: 'SET_LOADING', payload: false });
145+
}
127146
}
128147

129148
const truncatedTitle = item?.title?.length > 28 ? `${item.title.substring(0, 28)} ...` : item.title

frontend/src/components/ChatHistory/ChatHistoryPanel.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ const mockState = {
5353
isGenerating: false,
5454
isRequestInitiated: false,
5555
failedSections : [],
56-
isFailedReqInitiated : false
56+
isFailedReqInitiated : false,
57+
isLoading : false,
5758
};
5859

5960
const mockDispatch = jest.fn();

frontend/src/components/ChatHistory/ChatHistoryPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export function ChatHistoryPanel(_props: ChatHistoryPanelProps) {
7373
const handleHistoryClick = () => {
7474
appStateContext?.dispatch({ type: 'TOGGLE_CHAT_HISTORY' })
7575
}
76-
76+
7777
const onShowContextualMenu = React.useCallback((ev: React.MouseEvent<HTMLElement>) => {
7878
ev.preventDefault() // don't navigate
7979
setShowContextualMenu(true)

frontend/src/components/DraftCards/SectionCard.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ const mockState = {
5555
isGenerating: false,
5656
isRequestInitiated: false,
5757
failedSections : [],
58-
isFailedReqInitiated : false
58+
isFailedReqInitiated : false,
59+
isLoading : false,
5960
}
6061

6162
const renderWithContext = (idx = 0) =>

frontend/src/components/Sidebar/Sidebar.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ const mockState = {
5353
isGenerating: false,
5454
isRequestInitiated: false,
5555
failedSections : [],
56-
isFailedReqInitiated : false
56+
isFailedReqInitiated : false,
57+
isLoading : false,
5758
};
5859
const mockState2 = {
5960
isChatHistoryOpen: false,

frontend/src/pages/chat/Chat.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
IStackTokens,
1111
mergeStyleSets,
1212
IModalStyles,
13-
PrimaryButton
13+
PrimaryButton,
14+
Spinner,
15+
SpinnerSize
1416
} from '@fluentui/react'
1517
import { SquareRegular, ShieldLockRegular, ErrorCircleRegular } from '@fluentui/react-icons'
1618

@@ -46,6 +48,7 @@ import { AuthNotConfigure } from './Components/AuthNotConfigure'
4648
import { ChatMessageContainer } from './Components/ChatMessageContainer';
4749
import { parseErrorMessage, cleanJSON } from '../../helpers/helpers';
4850

51+
4952
const enum messageStatus {
5053
NotRunning = 'Not Running',
5154
Processing = 'Processing',
@@ -119,6 +122,11 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
119122
const [isModalOpen, setIsModalOpen] = useState(false)
120123
const [modalUrl, setModalUrl] = useState('');
121124
const [finalMessages, setFinalMessages] = useState<ChatMessage[]>([])
125+
if (!appStateContext || !appStateContext.state) {
126+
console.error("AppStateContext is undefined. Ensure AppProvider wraps this component.");
127+
return null; // Prevents execution if context is missing
128+
}
129+
const { currentChat } = appStateContext?.state;
122130

123131
const errorDialogContentProps = {
124132
type: DialogType.close,
@@ -422,6 +430,9 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
422430
let conversation
423431
if (conversationId) {
424432
conversation = appStateContext?.state?.chatHistory?.find(conv => conv.id === conversationId)
433+
if(!conversation){
434+
conversation = appStateContext?.state?.currentChat
435+
}
425436
if (!conversation) {
426437
console.error('Conversation not found.')
427438
setIsLoading(false)
@@ -460,6 +471,9 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
460471
let resultConversation
461472
if (conversationId) {
462473
resultConversation = appStateContext?.state?.chatHistory?.find(conv => conv.id === conversationId)
474+
if(!resultConversation){
475+
resultConversation = appStateContext?.state?.currentChat
476+
}
463477
if (!resultConversation) {
464478
console.error('Conversation not found.')
465479
setIsLoading(false)
@@ -530,6 +544,9 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
530544
let resultConversation
531545
if (conversationId) {
532546
resultConversation = appStateContext?.state?.chatHistory?.find(conv => conv.id === conversationId)
547+
if(!resultConversation){
548+
resultConversation = appStateContext?.state?.currentChat
549+
}
533550
if (!resultConversation) {
534551
console.error('Conversation not found.')
535552
setIsLoading(false)
@@ -585,6 +602,9 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
585602
let resultConversation
586603
if (conversationId) {
587604
resultConversation = appStateContext?.state?.chatHistory?.find(conv => conv.id === conversationId)
605+
if(!resultConversation){
606+
resultConversation = appStateContext?.state?.currentChat
607+
}
588608
if (!resultConversation) {
589609
console.error('Conversation not found.')
590610
setIsLoading(false)
@@ -817,19 +837,23 @@ const Chat = ({ type = ChatType.Browse }: Props) => {
817837
) : (
818838
<Stack horizontal className={styles.chatRoot}>
819839
<div className={styles.chatContainer}>
820-
{!messages || messages.length < 1 ? (
840+
{ appStateContext.state.isLoading ? (
841+
<Stack horizontalAlign="center" verticalAlign="center" className={styles.chatLoadingState} style={{padding: 250, paddingBottom: 150}}>
842+
<Spinner label="Loading your chat..." size={SpinnerSize.large} />
843+
</Stack>
844+
): currentChat?.messages && currentChat.messages.length > 0 ? (
845+
<ChatMessageContainer
846+
messages={currentChat.messages}
847+
isLoading={isLoading}
848+
type={type}
849+
onShowCitation={onShowCitation}
850+
showLoadingMessage={showLoadingMessage}
851+
ref={chatMessageStreamEnd}
852+
/>
853+
) : (
821854
<Stack className={styles.chatEmptyState}>
822855
<h1 className={styles.chatEmptyStateTitle}>{ui?.chat_title}</h1>
823856
</Stack>
824-
) : (
825-
<ChatMessageContainer
826-
messages={messages}
827-
isLoading={isLoading}
828-
type={type}
829-
onShowCitation={onShowCitation}
830-
showLoadingMessage={showLoadingMessage}
831-
ref = {chatMessageStreamEnd}
832-
/>
833857
)}
834858

835859
<Stack horizontal className={styles.chatInput}>

frontend/src/pages/layout/Layout.tsx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Link, Outlet, useLocation } from 'react-router-dom'
33
import { Dialog, Stack, TextField } from '@fluentui/react'
44
import { CopyRegular } from '@fluentui/react-icons'
55

6-
import { CosmosDBStatus } from '../../api'
6+
import { CosmosDBStatus, Conversation, historyList, ChatHistoryLoadingState } from '../../api'
77
import Contoso from '../../assets/Contoso.svg'
88
import { HistoryButton, ShareButton } from '../../components/common/Button'
99
import { AppStateContext } from '../../state/AppProvider'
@@ -39,6 +39,49 @@ const Layout = () => {
3939

4040
const handleHistoryClick = () => {
4141
appStateContext?.dispatch({ type: 'TOGGLE_CHAT_HISTORY' })
42+
43+
// Fetch chat history if it's not already loaded
44+
if(!appStateContext?.state.chatHistory) {
45+
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY_LOADING_STATE', payload: ChatHistoryLoadingState.Loading })
46+
fetchChatHistory()
47+
.then(res => {
48+
if (res) {
49+
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY_LOADING_STATE', payload: ChatHistoryLoadingState.Success })
50+
} else {
51+
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY_LOADING_STATE', payload: ChatHistoryLoadingState.Fail })
52+
appStateContext?.dispatch({
53+
type: 'SET_COSMOSDB_STATUS',
54+
payload: { cosmosDB: false, status: CosmosDBStatus.NotWorking }
55+
})
56+
}
57+
})
58+
.catch(_err => {
59+
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY_LOADING_STATE', payload: ChatHistoryLoadingState.Fail })
60+
appStateContext?.dispatch({
61+
type: 'SET_COSMOSDB_STATUS',
62+
payload: { cosmosDB: false, status: CosmosDBStatus.NotWorking }
63+
})
64+
})
65+
}
66+
}
67+
68+
const fetchChatHistory = async (offset = 0): Promise<Conversation[] | null> => {
69+
const result = await historyList(offset)
70+
.then(response => {
71+
if (response) {
72+
appStateContext?.dispatch({ type: 'FETCH_CHAT_HISTORY', payload: response })
73+
} else {
74+
appStateContext?.dispatch({ type: 'FETCH_CHAT_HISTORY', payload: null })
75+
}
76+
return response
77+
})
78+
.catch(_err => {
79+
appStateContext?.dispatch({ type: 'UPDATE_CHAT_HISTORY_LOADING_STATE', payload: ChatHistoryLoadingState.Fail })
80+
appStateContext?.dispatch({ type: 'FETCH_CHAT_HISTORY', payload: null })
81+
console.error('There was an issue fetching your data.')
82+
return null
83+
})
84+
return result
4285
}
4386

4487
useEffect(() => {

0 commit comments

Comments
 (0)