diff --git a/src/components/Chat/Chat.tsx b/src/components/Chat/Chat.tsx
index df834b116d..0c7af563db 100644
--- a/src/components/Chat/Chat.tsx
+++ b/src/components/Chat/Chat.tsx
@@ -110,6 +110,10 @@ export const Chat = memo(() => {
return isReplay && !messageIsStreaming && isReplayPaused;
}, [isReplay, isReplayPaused, messageIsStreaming]);
+ const isNotEmptyConversations = selectedConversations.some(
+ (conv) => conv.messages.length > 0,
+ );
+
useEffect(() => {
setIsShowChatSettings(false);
@@ -499,12 +503,6 @@ export const Chat = memo(() => {
setInputHeight(inputHeight);
}, []);
- useEffect(() => {
- if (showReplayControls) {
- setInputHeight(80);
- }
- }, [showReplayControls]);
-
return (
{modelError ? (
@@ -786,42 +784,37 @@ export const Chat = memo(() => {
) : (
<>
- {showReplayControls ? (
-
conv.messages.length === 0,
- )}
- />
- ) : (
- <>
- {!isPlayback && (
- val.messages.length > 0,
- )}
- showScrollDownButton={showScrollDownButton}
- onSend={onSendMessage}
- onScrollDownClick={handleScrollDown}
- onRegenerate={onRegenerateMessage}
- onStopConversation={() => {
- dispatch(ConversationsActions.stopStreamMessage());
- }}
- onResize={onChatInputResize}
+ {!isPlayback && (
+ {
+ dispatch(ConversationsActions.stopStreamMessage());
+ }}
+ onResize={onChatInputResize}
+ isShowInput={!isReplay || isNotEmptyConversations}
+ >
+ {showReplayControls && (
+
)}
+
+ )}
- {isPlayback && (
-
- )}
- >
+ {isPlayback && (
+
)}
>
)}
diff --git a/src/components/Chat/ChatInput.tsx b/src/components/Chat/ChatInput.tsx
index b1cd4901ec..fc59a2f5c2 100644
--- a/src/components/Chat/ChatInput.tsx
+++ b/src/components/Chat/ChatInput.tsx
@@ -1,34 +1,16 @@
import { IconPlayerStop } from '@tabler/icons-react';
-import {
- KeyboardEvent,
- MutableRefObject,
- useCallback,
- useEffect,
- useMemo,
- useRef,
- useState,
-} from 'react';
+import { MutableRefObject, ReactNode, useEffect, useRef } from 'react';
import { useTranslation } from 'next-i18next';
-import { isMobile } from '@/src/utils/app/mobile';
-
import { Message } from '@/src/types/chat';
-import { OpenAIEntityModels, defaultModelLimits } from '@/src/types/openai';
-import { Prompt } from '@/src/types/prompt';
import { ConversationsSelectors } from '@/src/store/conversations/conversations.reducers';
import { useAppSelector } from '@/src/store/hooks';
-import { ModelsSelectors } from '@/src/store/models/models.reducers';
-import { PromptsSelectors } from '@/src/store/prompts/prompts.reducers';
-import { SettingsSelectors } from '@/src/store/settings/settings.reducers';
import RefreshCWAlt from '../../../public/images/icons/refresh-cw-alt.svg';
-import { FooterMessage } from './FooterMessage';
-import { PromptDialog } from './PromptDialog';
-import { PromptList } from './PromptList';
-import { ScrollDownButton } from './ScrollDownButton';
-import { SendMessageButton } from './SendMessageButton';
+import { ChatInputFooter } from './ChatInputFooter';
+import { ChatInputMessage } from './ChatInputMessage';
interface Props {
onSend: (message: Message) => void;
@@ -39,6 +21,8 @@ interface Props {
textareaRef: MutableRefObject;
showScrollDownButton: boolean;
isMessagesPresented: boolean;
+ isShowInput: boolean;
+ children?: ReactNode;
}
export const ChatInput = ({
@@ -50,59 +34,17 @@ export const ChatInput = ({
textareaRef,
showScrollDownButton,
isMessagesPresented,
+ isShowInput,
+ children,
}: Props) => {
const { t } = useTranslation('chat');
- const [content, setContent] = useState();
- const [isTyping, setIsTyping] = useState(false);
- const [showPromptList, setShowPromptList] = useState(false);
- const [activePromptIndex, setActivePromptIndex] = useState(0);
- const [promptInputValue, setPromptInputValue] = useState('');
- const [variables, setVariables] = useState([]);
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [showPluginSelect, setShowPluginSelect] = useState(false);
-
- const prompts = useAppSelector(PromptsSelectors.selectPrompts);
-
const messageIsStreaming = useAppSelector(
ConversationsSelectors.selectIsConversationsStreaming,
);
- const isIframe = useAppSelector(SettingsSelectors.selectIsIframe);
- const selectedConversations = useAppSelector(
- ConversationsSelectors.selectSelectedConversations,
- );
-
- const modelsMap = useAppSelector(ModelsSelectors.selectModelsMap);
-
- const maxLength = useMemo(() => {
- const maxLengthArray = selectedConversations.map(
- ({ model }) =>
- modelsMap[model.id]?.maxLength ??
- OpenAIEntityModels[model.id]?.maxLength ??
- defaultModelLimits.maxLength,
- );
-
- return Math.min(...maxLengthArray);
- }, [modelsMap, selectedConversations]);
-
- const promptListRef = useRef(null);
const inputRef = useRef(null);
- const [filteredPrompts, setFilteredPrompts] = useState(() =>
- prompts.filter((prompt) =>
- prompt.name.toLowerCase().includes(promptInputValue.toLowerCase()),
- ),
- );
-
- useEffect(() => {
- setFilteredPrompts(
- prompts.filter((prompt) =>
- prompt.name.toLowerCase().includes(promptInputValue.toLowerCase()),
- ),
- );
- }, [prompts, promptInputValue]);
-
useEffect(() => {
if (!inputRef) {
return;
@@ -118,203 +60,6 @@ export const ChatInput = ({
};
}, [inputRef, onResize]);
- const updatePromptListVisibility = useCallback((text: string) => {
- const match = text.match(/\/\w*$/);
-
- if (match) {
- setShowPromptList(true);
- setPromptInputValue(match[0].slice(1));
- } else {
- setShowPromptList(false);
- setPromptInputValue('');
- }
- }, []);
-
- const handleChange = useCallback(
- (e: React.ChangeEvent) => {
- const value = e.target.value;
-
- if (maxLength && value.length > maxLength) {
- alert(
- t(
- `Message limit is {{maxLength}} characters. You have entered {{valueLength}} characters.`,
- { maxLength, valueLength: value.length },
- ),
- );
- return;
- }
-
- setContent(value);
- updatePromptListVisibility(value);
- },
- [maxLength, t, updatePromptListVisibility],
- );
-
- const handleSend = useCallback(() => {
- if (messageIsStreaming) {
- return;
- }
-
- if (!content) {
- alert(t('Please enter a message'));
- return;
- }
-
- onSend({ role: 'user', content });
- setContent('');
-
- if (window.innerWidth < 640 && textareaRef && textareaRef.current) {
- textareaRef.current.blur();
- }
- }, [content, messageIsStreaming, onSend, t, textareaRef]);
-
- const parseVariables = useCallback((content: string) => {
- const regex = /{{(.*?)}}/g;
- const foundVariables = [];
- let match;
-
- while ((match = regex.exec(content)) !== null) {
- foundVariables.push(match[1]);
- }
-
- return foundVariables;
- }, []);
-
- const handlePromptSelect = useCallback(
- (prompt: Prompt) => {
- if (!prompt.content) {
- return;
- }
-
- const parsedVariables = parseVariables(prompt.content);
- setVariables(parsedVariables);
-
- if (parsedVariables.length > 0) {
- setIsModalVisible(true);
- } else {
- setContent((prevContent) => {
- const updatedContent = prevContent?.replace(
- /\/\w*$/,
- prompt.content as string,
- );
- return updatedContent;
- });
- updatePromptListVisibility(prompt.content);
- }
- },
- [parseVariables, updatePromptListVisibility],
- );
-
- const handleInitModal = useCallback(() => {
- const selectedPrompt = filteredPrompts[activePromptIndex];
- if (selectedPrompt && !!selectedPrompt.content) {
- setContent((prevContent) => {
- const newContent = prevContent?.replace(
- /\/\w*$/,
- selectedPrompt.content as string,
- );
- return newContent;
- });
- handlePromptSelect(selectedPrompt);
- }
- setShowPromptList(false);
- }, [activePromptIndex, filteredPrompts, handlePromptSelect]);
-
- const handleKeyDown = useCallback(
- (e: KeyboardEvent) => {
- if (showPromptList) {
- if (e.key === 'ArrowDown') {
- e.preventDefault();
- setActivePromptIndex((prevIndex) =>
- prevIndex < prompts.length - 1 ? prevIndex + 1 : prevIndex,
- );
- } else if (e.key === 'ArrowUp') {
- e.preventDefault();
- setActivePromptIndex((prevIndex) =>
- prevIndex > 0 ? prevIndex - 1 : prevIndex,
- );
- } else if (e.key === 'Tab') {
- e.preventDefault();
- setActivePromptIndex((prevIndex) =>
- prevIndex < prompts.length - 1 ? prevIndex + 1 : 0,
- );
- } else if (e.key === 'Enter') {
- e.preventDefault();
- handleInitModal();
- } else if (e.key === 'Escape') {
- e.preventDefault();
- setShowPromptList(false);
- } else {
- setActivePromptIndex(0);
- }
- } else if (e.key === 'Enter' && !isTyping && !isMobile() && !e.shiftKey) {
- e.preventDefault();
- handleSend();
- } else if (e.key === '/' && e.metaKey) {
- e.preventDefault();
- setShowPluginSelect(!showPluginSelect);
- }
- },
- [
- handleInitModal,
- handleSend,
- isTyping,
- prompts.length,
- showPluginSelect,
- showPromptList,
- ],
- );
-
- const handleSubmit = useCallback(
- (updatedVariables: string[]) => {
- const newContent = content?.replace(/{{(.*?)}}/g, (match, variable) => {
- const index = variables.indexOf(variable);
- return updatedVariables[index];
- });
-
- setContent(newContent);
-
- if (textareaRef && textareaRef.current) {
- textareaRef.current.focus();
- }
- },
- [content, textareaRef, variables],
- );
-
- useEffect(() => {
- if (promptListRef.current) {
- promptListRef.current.scrollTop = activePromptIndex * 30;
- }
- }, [activePromptIndex]);
-
- useEffect(() => {
- if (textareaRef && textareaRef.current) {
- textareaRef.current.style.height = 'inherit'; // reset height
- const scrollHeight = textareaRef.current.scrollHeight; // then check scroll height
- textareaRef.current.style.height = `${scrollHeight}px`;
- textareaRef.current.style.overflow = `${
- scrollHeight > 400 ? 'auto' : 'hidden'
- }`;
- }
- }, [content, textareaRef]);
-
- useEffect(() => {
- const handleOutsideClick = (e: MouseEvent) => {
- if (
- promptListRef.current &&
- !promptListRef.current.contains(e.target as Node)
- ) {
- setShowPromptList(false);
- }
- };
-
- window.addEventListener('click', handleOutsideClick);
-
- return () => {
- window.removeEventListener('click', handleOutsideClick);
- };
- }, []);
-
return (
)}
- {!messageIsStreaming && isMessagesPresented && (
+ {!children && !messageIsStreaming && isMessagesPresented && (
-
-
-
-
-
-
+ {isShowInput && (
+
+ )}
+
);
};
diff --git a/src/components/Chat/ChatInputFooter.tsx b/src/components/Chat/ChatInputFooter.tsx
new file mode 100644
index 0000000000..7d4dca0c2a
--- /dev/null
+++ b/src/components/Chat/ChatInputFooter.tsx
@@ -0,0 +1,9 @@
+import { FooterMessage } from './FooterMessage';
+
+export const ChatInputFooter = () => {
+ return (
+
+
+
+ );
+};
diff --git a/src/components/Chat/ChatInputMessage.tsx b/src/components/Chat/ChatInputMessage.tsx
new file mode 100644
index 0000000000..5f698b7c84
--- /dev/null
+++ b/src/components/Chat/ChatInputMessage.tsx
@@ -0,0 +1,331 @@
+import {
+ KeyboardEvent,
+ MutableRefObject,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+
+import { useTranslation } from 'next-i18next';
+
+import { isMobile } from '@/src/utils/app/mobile';
+
+import { Message } from '@/src/types/chat';
+import { OpenAIEntityModels, defaultModelLimits } from '@/src/types/openai';
+import { Prompt } from '@/src/types/prompt';
+
+import { ConversationsSelectors } from '@/src/store/conversations/conversations.reducers';
+import { useAppSelector } from '@/src/store/hooks';
+import { ModelsSelectors } from '@/src/store/models/models.reducers';
+import { PromptsSelectors } from '@/src/store/prompts/prompts.reducers';
+import { SettingsSelectors } from '@/src/store/settings/settings.reducers';
+
+import { PromptDialog } from './PromptDialog';
+import { PromptList } from './PromptList';
+import { ScrollDownButton } from './ScrollDownButton';
+import { SendMessageButton } from './SendMessageButton';
+
+interface Props {
+ textareaRef: MutableRefObject;
+ showScrollDownButton: boolean;
+ onScrollDownClick: () => void;
+ onSend: (message: Message) => void;
+}
+
+export const ChatInputMessage = ({
+ textareaRef,
+ showScrollDownButton,
+ onScrollDownClick,
+ onSend,
+}: Props) => {
+ const { t } = useTranslation('chat');
+
+ const [content, setContent] = useState();
+ const [isTyping, setIsTyping] = useState(false);
+ const [showPromptList, setShowPromptList] = useState(false);
+ const [activePromptIndex, setActivePromptIndex] = useState(0);
+ const [promptInputValue, setPromptInputValue] = useState('');
+ const [variables, setVariables] = useState([]);
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const [showPluginSelect, setShowPluginSelect] = useState(false);
+
+ const prompts = useAppSelector(PromptsSelectors.selectPrompts);
+ const isIframe = useAppSelector(SettingsSelectors.selectIsIframe);
+ const messageIsStreaming = useAppSelector(
+ ConversationsSelectors.selectIsConversationsStreaming,
+ );
+ const selectedConversations = useAppSelector(
+ ConversationsSelectors.selectSelectedConversations,
+ );
+ const modelsMap = useAppSelector(ModelsSelectors.selectModelsMap);
+ const isReplay = useAppSelector(
+ ConversationsSelectors.selectIsReplaySelectedConversations,
+ );
+
+ const [filteredPrompts, setFilteredPrompts] = useState(() =>
+ prompts.filter((prompt) =>
+ prompt.name.toLowerCase().includes(promptInputValue.toLowerCase()),
+ ),
+ );
+
+ const maxLength = useMemo(() => {
+ const maxLengthArray = selectedConversations.map(
+ ({ model }) =>
+ modelsMap[model.id]?.maxLength ??
+ OpenAIEntityModels[model.id]?.maxLength ??
+ defaultModelLimits.maxLength,
+ );
+
+ return Math.min(...maxLengthArray);
+ }, [modelsMap, selectedConversations]);
+
+ const updatePromptListVisibility = useCallback((text: string) => {
+ const match = text.match(/\/\w*$/);
+
+ if (match) {
+ setShowPromptList(true);
+ setPromptInputValue(match[0].slice(1));
+ } else {
+ setShowPromptList(false);
+ setPromptInputValue('');
+ }
+ }, []);
+
+ const handleChange = useCallback(
+ (e: React.ChangeEvent) => {
+ const value = e.target.value;
+
+ if (maxLength && value.length > maxLength) {
+ alert(
+ t(
+ `Message limit is {{maxLength}} characters. You have entered {{valueLength}} characters.`,
+ { maxLength, valueLength: value.length },
+ ),
+ );
+ return;
+ }
+
+ setContent(value);
+ updatePromptListVisibility(value);
+ },
+ [maxLength, t, updatePromptListVisibility],
+ );
+
+ const handleSend = useCallback(() => {
+ if (messageIsStreaming) {
+ return;
+ }
+
+ if (!content) {
+ alert(t('Please enter a message'));
+ return;
+ }
+
+ onSend({ role: 'user', content });
+ setContent('');
+
+ if (window.innerWidth < 640 && textareaRef && textareaRef.current) {
+ textareaRef.current.blur();
+ }
+ }, [content, messageIsStreaming, onSend, t, textareaRef]);
+
+ const parseVariables = useCallback((content: string) => {
+ const regex = /{{(.*?)}}/g;
+ const foundVariables = [];
+ let match;
+
+ while ((match = regex.exec(content)) !== null) {
+ foundVariables.push(match[1]);
+ }
+
+ return foundVariables;
+ }, []);
+
+ const handlePromptSelect = useCallback(
+ (prompt: Prompt) => {
+ if (!prompt.content) {
+ return;
+ }
+
+ const parsedVariables = parseVariables(prompt.content);
+ setVariables(parsedVariables);
+
+ if (parsedVariables.length > 0) {
+ setIsModalVisible(true);
+ } else {
+ setContent((prevContent) => {
+ const updatedContent = prevContent?.replace(
+ /\/\w*$/,
+ prompt.content as string,
+ );
+ return updatedContent;
+ });
+ updatePromptListVisibility(prompt.content);
+ }
+ },
+ [parseVariables, updatePromptListVisibility],
+ );
+
+ const handleInitModal = useCallback(() => {
+ const selectedPrompt = filteredPrompts[activePromptIndex];
+ if (selectedPrompt && !!selectedPrompt.content) {
+ setContent((prevContent) => {
+ const newContent = prevContent?.replace(
+ /\/\w*$/,
+ selectedPrompt.content as string,
+ );
+ return newContent;
+ });
+ handlePromptSelect(selectedPrompt);
+ }
+ setShowPromptList(false);
+ }, [activePromptIndex, filteredPrompts, handlePromptSelect]);
+
+ const handleKeyDown = useCallback(
+ (e: KeyboardEvent) => {
+ if (showPromptList) {
+ if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ setActivePromptIndex((prevIndex) =>
+ prevIndex < prompts.length - 1 ? prevIndex + 1 : prevIndex,
+ );
+ } else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ setActivePromptIndex((prevIndex) =>
+ prevIndex > 0 ? prevIndex - 1 : prevIndex,
+ );
+ } else if (e.key === 'Tab') {
+ e.preventDefault();
+ setActivePromptIndex((prevIndex) =>
+ prevIndex < prompts.length - 1 ? prevIndex + 1 : 0,
+ );
+ } else if (e.key === 'Enter') {
+ e.preventDefault();
+ handleInitModal();
+ } else if (e.key === 'Escape') {
+ e.preventDefault();
+ setShowPromptList(false);
+ } else {
+ setActivePromptIndex(0);
+ }
+ } else if (e.key === 'Enter' && !isTyping && !isMobile() && !e.shiftKey) {
+ e.preventDefault();
+ if (isReplay) {
+ return;
+ }
+ handleSend();
+ } else if (e.key === '/' && e.metaKey) {
+ e.preventDefault();
+ setShowPluginSelect(!showPluginSelect);
+ }
+ },
+ [
+ handleInitModal,
+ handleSend,
+ isTyping,
+ prompts.length,
+ showPluginSelect,
+ showPromptList,
+ ],
+ );
+
+ const handleSubmit = useCallback(
+ (updatedVariables: string[]) => {
+ const newContent = content?.replace(/{{(.*?)}}/g, (match, variable) => {
+ const index = variables.indexOf(variable);
+ return updatedVariables[index];
+ });
+
+ setContent(newContent);
+
+ if (textareaRef && textareaRef.current) {
+ textareaRef.current.focus();
+ }
+ },
+ [content, textareaRef, variables],
+ );
+
+ useEffect(() => {
+ setFilteredPrompts(
+ prompts.filter((prompt) =>
+ prompt.name.toLowerCase().includes(promptInputValue.toLowerCase()),
+ ),
+ );
+ }, [prompts, promptInputValue]);
+
+ useEffect(() => {
+ if (textareaRef && textareaRef.current) {
+ textareaRef.current.style.height = 'inherit'; // reset height
+ const scrollHeight = textareaRef.current.scrollHeight; // then check scroll height
+ textareaRef.current.style.height = `${scrollHeight}px`;
+ textareaRef.current.style.overflow = `${
+ scrollHeight > 400 ? 'auto' : 'hidden'
+ }`;
+ }
+ }, [content, textareaRef]);
+
+ return (
+
+ );
+};
diff --git a/src/components/Chat/ChatReplayControls.tsx b/src/components/Chat/ChatReplayControls.tsx
index cc6d994c3c..220a3ab227 100644
--- a/src/components/Chat/ChatReplayControls.tsx
+++ b/src/components/Chat/ChatReplayControls.tsx
@@ -23,13 +23,10 @@ const ChatReplayControls: FC = ({
ConversationsSelectors.selectIsErrorReplayConversations,
);
return (
-
+ <>
{showReplayStart ? (
) : (
)}
-
+ >
);
};
diff --git a/src/components/Chat/PlaybackControls.tsx b/src/components/Chat/PlaybackControls.tsx
index 08cfc035e9..d28a187db7 100644
--- a/src/components/Chat/PlaybackControls.tsx
+++ b/src/components/Chat/PlaybackControls.tsx
@@ -13,9 +13,10 @@ import {
} from '@/src/store/conversations/conversations.reducers';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';
-import { FooterMessage } from '@/src/components/Chat/FooterMessage';
import { ScrollDownButton } from '@/src/components/Chat/ScrollDownButton';
+import { ChatInputFooter } from './ChatInputFooter';
+
interface Props {
showScrollDownButton: boolean;
onScrollDownClick: () => void;
@@ -193,9 +194,7 @@ export const PlaybackControls = ({
/>
)}
-
-
-
+
);
};
diff --git a/src/components/Chat/PromptList.tsx b/src/components/Chat/PromptList.tsx
index 9cde765933..84536666d5 100644
--- a/src/components/Chat/PromptList.tsx
+++ b/src/components/Chat/PromptList.tsx
@@ -1,4 +1,5 @@
-import { FC, MutableRefObject } from 'react';
+import { useDismiss, useFloating, useInteractions } from '@floating-ui/react';
+import { FC, useEffect } from 'react';
import { Prompt } from '@/src/types/prompt';
@@ -6,20 +7,39 @@ interface Props {
prompts: Prompt[];
activePromptIndex: number;
onSelect: () => void;
- onMouseOver: (index: number) => void;
- promptListRef: MutableRefObject;
+ onMouseEnter: (index: number) => void;
+ onClose: () => void;
+ isOpen: boolean;
}
export const PromptList: FC = ({
prompts,
activePromptIndex,
onSelect,
- onMouseOver,
- promptListRef,
+ onMouseEnter,
+ onClose,
+ isOpen,
}) => {
+ const { refs, context } = useFloating({
+ open: isOpen,
+ onOpenChange: () => {
+ onClose();
+ },
+ });
+
+ const dismiss = useDismiss(context);
+ const { getFloatingProps } = useInteractions([dismiss]);
+
+ useEffect(() => {
+ if (refs.floating.current) {
+ refs.floating.current.scrollTop = activePromptIndex * 30;
+ }
+ }, [activePromptIndex]);
+
return (
@@ -35,7 +55,7 @@ export const PromptList: FC = ({
onSelect();
}}
data-qa="prompt-option"
- onMouseEnter={() => onMouseOver(index)}
+ onMouseEnter={() => onMouseEnter(index)}
>
{prompt.name}
diff --git a/src/components/Chat/SendMessageButton.tsx b/src/components/Chat/SendMessageButton.tsx
index 42482e3c5b..07971ed8ad 100644
--- a/src/components/Chat/SendMessageButton.tsx
+++ b/src/components/Chat/SendMessageButton.tsx
@@ -16,20 +16,15 @@ interface Props {
interface SendIconTooltipProps {
isShowTooltip?: boolean;
- isError?: boolean;
+ tooltipContent?: string;
children: ReactNode;
}
const SendIconTooltip = ({
isShowTooltip,
- isError,
+ tooltipContent,
children,
}: SendIconTooltipProps) => {
- const { t } = useTranslation('chat');
-
- const tooltipContent = isError
- ? 'Please regenerate response to continue working with chat'
- : 'Please type a message';
return (
<>
{!isShowTooltip ? (
@@ -37,7 +32,7 @@ const SendIconTooltip = ({
) : (
{children}
- {t(tooltipContent)}
+ {tooltipContent && {tooltipContent}}
)}
>
@@ -45,6 +40,7 @@ const SendIconTooltip = ({
};
export const SendMessageButton = ({ handleSend, isInputEmpty }: Props) => {
+ const { t } = useTranslation('chat');
const isModelsLoading = useAppSelector(ModelsSelectors.selectModelsIsLoading);
const isMessageError = useAppSelector(
ConversationsSelectors.selectIsMessagesError,
@@ -58,17 +54,30 @@ export const SendMessageButton = ({ handleSend, isInputEmpty }: Props) => {
const messageIsStreaming = useAppSelector(
ConversationsSelectors.selectIsConversationsStreaming,
);
+ const isReplay = useAppSelector(
+ ConversationsSelectors.selectIsReplaySelectedConversations,
+ );
const isError =
isLastAssistantMessageEmpty || (isMessageError && notModelConversations);
+ const tooltipContent = (): string => {
+ if (isReplay) {
+ return t('Please continue replay to continue working with chat');
+ }
+ if (isError) {
+ return t('Please regenerate response to continue working with chat');
+ }
+ return t('Please type a message');
+ };
+
+ const isShowDisabled = isError || isInputEmpty || isReplay;
+
return (