Add Up and Down arrow functionality to chat messages (#3440)

* Add Up and Down arrow functionality to chat messages

- Works like Linux shell
- History limited to 10 messages

* Fix linting errors

* Update EmbedChat.jsx

---------

Co-authored-by: Henry Heng <henryheng@flowiseai.com>
This commit is contained in:
Tyler 2024-11-08 18:43:33 -06:00 committed by GitHub
parent d64cb7028b
commit 835b1511d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 79 additions and 1 deletions

View File

@ -0,0 +1,62 @@
export class ChatInputHistory {
constructor(maxHistory = 10) {
this.history = []
this.currentIndex = -1
this.tempInput = ''
this.maxHistory = maxHistory
this.loadHistory()
}
addToHistory(input) {
if (!input.trim()) return
if (this.history[0] !== input) {
this.history.unshift(input)
if (this.history.length > this.maxHistory) {
this.history.pop()
}
}
this.currentIndex = -1
this.saveHistory()
}
getPreviousInput(currentInput) {
if (this.currentIndex === -1) {
this.tempInput = currentInput
}
if (this.currentIndex < this.history.length - 1) {
this.currentIndex++
return this.history[this.currentIndex]
}
return this.history[this.currentIndex] || this.tempInput
}
getNextInput() {
if (this.currentIndex > -1) {
this.currentIndex--
if (this.currentIndex === -1) {
return this.tempInput
}
return this.history[this.currentIndex]
}
return this.tempInput
}
saveHistory() {
try {
localStorage.setItem('chatInputHistory', JSON.stringify(this.history))
} catch (error) {
console.warn('Failed to save chat history to localStorage:', error)
}
}
loadHistory() {
try {
const saved = localStorage.getItem('chatInputHistory')
if (saved) {
this.history = JSON.parse(saved)
}
} catch (error) {
console.warn('Failed to load chat history from localStorage:', error)
}
}
}

View File

@ -83,6 +83,9 @@ import { isValidURL, removeDuplicateURL, setLocalStorageChatflow, getLocalStorag
import useNotifier from '@/utils/useNotifier' import useNotifier from '@/utils/useNotifier'
import FollowUpPromptsCard from '@/ui-component/cards/FollowUpPromptsCard' import FollowUpPromptsCard from '@/ui-component/cards/FollowUpPromptsCard'
// History
import { ChatInputHistory } from './ChatInputHistory'
const messageImageStyle = { const messageImageStyle = {
width: '128px', width: '128px',
height: '128px', height: '128px',
@ -185,6 +188,7 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
const [uploadedFiles, setUploadedFiles] = useState([]) const [uploadedFiles, setUploadedFiles] = useState([])
const [imageUploadAllowedTypes, setImageUploadAllowedTypes] = useState('') const [imageUploadAllowedTypes, setImageUploadAllowedTypes] = useState('')
const [fileUploadAllowedTypes, setFileUploadAllowedTypes] = useState('') const [fileUploadAllowedTypes, setFileUploadAllowedTypes] = useState('')
const [inputHistory] = useState(new ChatInputHistory(10))
const inputRef = useRef(null) const inputRef = useRef(null)
const getChatmessageApi = useApi(chatmessageApi.getInternalChatmessageFromChatflow) const getChatmessageApi = useApi(chatmessageApi.getInternalChatmessageFromChatflow)
@ -768,6 +772,10 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
if (selectedInput !== undefined && selectedInput.trim() !== '') input = selectedInput if (selectedInput !== undefined && selectedInput.trim() !== '') input = selectedInput
if (input.trim()) {
inputHistory.addToHistory(input)
}
setLoading(true) setLoading(true)
let uploads = previews.map((item) => { let uploads = previews.map((item) => {
return { return {
@ -934,7 +942,15 @@ export const ChatMessage = ({ open, chatflowid, isAgentCanvas, isDialog, preview
const handleEnter = (e) => { const handleEnter = (e) => {
// Check if IME composition is in progress // Check if IME composition is in progress
const isIMEComposition = e.isComposing || e.keyCode === 229 const isIMEComposition = e.isComposing || e.keyCode === 229
if (e.key === 'Enter' && userInput && !isIMEComposition) { if (e.key === 'ArrowUp' && !isIMEComposition) {
e.preventDefault()
const previousInput = inputHistory.getPreviousInput(userInput)
setUserInput(previousInput)
} else if (e.key === 'ArrowDown' && !isIMEComposition) {
e.preventDefault()
const nextInput = inputHistory.getNextInput()
setUserInput(nextInput)
} else if (e.key === 'Enter' && userInput && !isIMEComposition) {
if (!e.shiftKey && userInput) { if (!e.shiftKey && userInput) {
handleSubmit(e) handleSubmit(e)
} }