mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Copilot Chat: Make message input box input persistent per chat within the UI (#1302)
### Motivation and Context Bug: When you enter something into the message input box in Copilot Chat but do not send it, and you switch to another chat session, the message will appear in the other chat session's message input box. Expected: You type a message in one of the chat sessions, the message should only appear in the input box of that chat session. And when you switch to another session, the input box should become empty or show whatever is already in there previously. ### Description 1. Remove the feature that enables users to go back to the previous message by pressing the up arrow key. 2. Fix the bug described above to enable the expected behavior.
This commit is contained in:
@@ -13,6 +13,7 @@ import { DocumentImportService } from '../../libs/services/DocumentImportService
|
||||
import { useAppDispatch, useAppSelector } from '../../redux/app/hooks';
|
||||
import { RootState } from '../../redux/app/store';
|
||||
import { addAlert } from '../../redux/features/app/appSlice';
|
||||
import { editConversationInput } from '../../redux/features/conversations/conversationsSlice';
|
||||
import { SpeechService } from './../../libs/services/SpeechService';
|
||||
import { TypingIndicatorRenderer } from './typing-indicator/TypingIndicatorRenderer';
|
||||
|
||||
@@ -67,13 +68,12 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
|
||||
const account = useAccount(accounts[0] || {});
|
||||
const dispatch = useAppDispatch();
|
||||
const [value, setValue] = React.useState('');
|
||||
const [previousValue, setPreviousValue] = React.useState('');
|
||||
const [recognizer, setRecognizer] = React.useState<speechSdk.SpeechRecognizer>();
|
||||
const [isListening, setIsListening] = React.useState(false);
|
||||
const [documentImporting, SetDocumentImporting] = React.useState(false);
|
||||
const documentImportService = new DocumentImportService(process.env.REACT_APP_BACKEND_URI as string);
|
||||
const documentFileRef = useRef<HTMLInputElement | null>(null);
|
||||
const { selectedId } = useAppSelector((state: RootState) => state.conversations);
|
||||
const { conversations, selectedId } = useAppSelector((state: RootState) => state.conversations);
|
||||
|
||||
React.useEffect(() => {
|
||||
async function initSpeechRecognizer() {
|
||||
@@ -88,6 +88,11 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
|
||||
initSpeechRecognizer();
|
||||
}, [instance, inProgress]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const chatState = conversations[selectedId];
|
||||
setValue(chatState.input);
|
||||
}, [conversations, selectedId]);
|
||||
|
||||
const handleSpeech = () => {
|
||||
setIsListening(true);
|
||||
if (recognizer) {
|
||||
@@ -136,8 +141,8 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
|
||||
return; // only submit if data is not empty
|
||||
}
|
||||
onSubmit(data);
|
||||
setPreviousValue(data);
|
||||
setValue('');
|
||||
dispatch(editConversationInput({ id: selectedId, newInput: '' }));
|
||||
} catch (error) {
|
||||
const message = `Error submitting chat input: ${(error as Error).message}`;
|
||||
log(message);
|
||||
@@ -148,7 +153,6 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
|
||||
}),
|
||||
);
|
||||
}
|
||||
// void chat.sendTypingStopSignalAsync();
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -168,19 +172,15 @@ export const ChatInput: React.FC<ChatInputProps> = (props) => {
|
||||
setValue(chatInput.value);
|
||||
}
|
||||
}}
|
||||
onChange={(_event, data) => setValue(data.value)}
|
||||
onChange={(_event, data) => {
|
||||
setValue(data.value);
|
||||
dispatch(editConversationInput({ id: selectedId, newInput: data.value }));
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
handleSubmit(value);
|
||||
return;
|
||||
} else if (value === '' && previousValue !== '' && event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
setValue(previousValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// void chat.sendTypingStartSignalAsync();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -80,6 +80,7 @@ export const useChat = () => {
|
||||
messages: chatMessages,
|
||||
users: [loggedInUser],
|
||||
botProfilePicture: getBotProfilePicture(Object.keys(conversations).length),
|
||||
input: '',
|
||||
};
|
||||
|
||||
dispatch(addConversation(newChat));
|
||||
@@ -184,6 +185,7 @@ export const useChat = () => {
|
||||
users: [loggedInUser],
|
||||
messages: chatMessages,
|
||||
botProfilePicture: getBotProfilePicture(Object.keys(loadedConversations).length),
|
||||
input: '',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -10,4 +10,5 @@ export interface ChatState {
|
||||
messages: IChatMessage[];
|
||||
botProfilePicture: string;
|
||||
lastUpdatedTimestamp?: number;
|
||||
input: string;
|
||||
}
|
||||
|
||||
+5
@@ -26,3 +26,8 @@ export interface ConversationTitleChange {
|
||||
id: string;
|
||||
newTitle: string;
|
||||
}
|
||||
|
||||
export interface ConversationInputChange {
|
||||
id: string;
|
||||
newInput: string;
|
||||
}
|
||||
|
||||
+7
-1
@@ -3,7 +3,7 @@
|
||||
import { createSlice, PayloadAction, Slice } from '@reduxjs/toolkit';
|
||||
import { ChatMessageState, IChatMessage } from '../../../libs/models/ChatMessage';
|
||||
import { ChatState } from './ChatState';
|
||||
import { Conversations, ConversationsState, ConversationTitleChange, initialState } from './ConversationsState';
|
||||
import { ConversationInputChange, Conversations, ConversationsState, ConversationTitleChange, initialState } from './ConversationsState';
|
||||
|
||||
export const conversationsSlice: Slice<ConversationsState> = createSlice({
|
||||
name: 'conversations',
|
||||
@@ -19,6 +19,11 @@ export const conversationsSlice: Slice<ConversationsState> = createSlice({
|
||||
state.conversations[id].lastUpdatedTimestamp = new Date().getTime();
|
||||
frontLoadChat(state, id);
|
||||
},
|
||||
editConversationInput: (state: ConversationsState, action: PayloadAction<ConversationInputChange>) => {
|
||||
const id = action.payload.id;
|
||||
const newInput = action.payload.newInput;
|
||||
state.conversations[id].input = newInput;
|
||||
},
|
||||
setSelectedConversation: (state: ConversationsState, action: PayloadAction<string>) => {
|
||||
state.selectedId = action.payload;
|
||||
},
|
||||
@@ -52,6 +57,7 @@ export const conversationsSlice: Slice<ConversationsState> = createSlice({
|
||||
export const {
|
||||
setConversations,
|
||||
editConversationTitle,
|
||||
editConversationInput,
|
||||
setSelectedConversation,
|
||||
addConversation,
|
||||
updateConversation,
|
||||
|
||||
Reference in New Issue
Block a user