From b9a071bc3927eed9f95be980920014094af9fad6 Mon Sep 17 00:00:00 2001 From: yzh990918 <251205668@qq.com> Date: Mon, 8 May 2023 17:05:10 +0800 Subject: [PATCH] feat: Improve the logical part of message-settings --- src/components/Send.tsx | 8 +- src/components/main/MessageItem.tsx | 127 ++++++++++++++++++------ src/components/ui/base/DropdownMenu.tsx | 9 +- src/logics/conversation.ts | 21 ++-- src/stores/messages.ts | 28 ++++++ src/stores/settings.ts | 3 +- src/types/provider.ts | 2 +- 7 files changed, 149 insertions(+), 49 deletions(-) diff --git a/src/components/Send.tsx b/src/components/Send.tsx index b2fd9c67..b84bc7b8 100644 --- a/src/components/Send.tsx +++ b/src/components/Send.tsx @@ -5,6 +5,7 @@ import { currentErrorMessage, isSendBoxFocus, scrollController } from '@/stores/ import { addConversation, conversationMap, currentConversationId } from '@/stores/conversation' import { loadingStateMap, streamsMap } from '@/stores/streams' import { handlePrompt } from '@/logics/conversation' +import { globalAbortController } from '@/stores/settings' export default () => { let inputRef: HTMLTextAreaElement @@ -14,7 +15,7 @@ export default () => { const $currentErrorMessage = useStore(currentErrorMessage) const $streamsMap = useStore(streamsMap) const $loadingStateMap = useStore(loadingStateMap) - const [controller, setController] = createSignal() + const $globalAbortController = useStore(globalAbortController) const [inputPrompt, setInputPrompt] = createSignal('') const isEditing = () => inputPrompt() || $isSendBoxFocus() @@ -96,12 +97,11 @@ export default () => { const clearPrompt = () => { setInputPrompt('') - inputRef.value = '' isSendBoxFocus.set(false) } const handleAbortFetch = () => { - controller()!.abort() + $globalAbortController()?.abort() clearPrompt() } @@ -124,7 +124,7 @@ export default () => { addConversation() const controller = new AbortController() - setController(controller) + globalAbortController.set(controller) handlePrompt(currentConversation(), inputRef.value, controller.signal) clearPrompt() scrollController().scrollToBottom() diff --git a/src/components/main/MessageItem.tsx b/src/components/main/MessageItem.tsx index f4825bcf..4e4bbe6c 100644 --- a/src/components/main/MessageItem.tsx +++ b/src/components/main/MessageItem.tsx @@ -1,9 +1,14 @@ -import { For } from 'solid-js/web' +import { For, Show } from 'solid-js/web' import { createSignal } from 'solid-js' +import { useStore } from '@nanostores/solid' import { useClipboardCopy } from '@/hooks' -import { deleteMessageByConversationId } from '@/stores/messages' +import { deleteMessageByConversationId, spliceMessageByConversationId, spliceUpdateMessageByConversationId } from '@/stores/messages' +import { conversationMap } from '@/stores/conversation' +import { handlePrompt } from '@/logics/conversation' +import { scrollController } from '@/stores/ui' +import { globalAbortController } from '@/stores/settings' import StreamableText from '../StreamableText' -import { Tooltip } from '../ui/base' +import { DropDownMenu, Tooltip } from '../ui/base' import type { MenuItem } from '../ui/base' import type { MessageInstance } from '@/types/message' @@ -15,28 +20,65 @@ interface Props { } export default (props: Props) => { - const roleClass = { - system: 'bg-gradient-to-b from-gray-300 via-gray-200 to-gray-300', - user: 'bg-gradient-to-b from-gray-300 via-gray-200 to-gray-300', - assistant: 'bg-gradient-to-b from-[#fccb90] to-[#d57eeb]', - } + const $conversationMap = useStore(conversationMap) - const [copied, copy] = useClipboardCopy(props.message.content) const [showRawCode, setShowRawCode] = createSignal(false) + const [copied, setCopied] = createSignal(false) + const [isEditing, setIsEditing] = createSignal(false) + let inputRef: HTMLTextAreaElement + const [inputPrompt, setInputPrompt] = createSignal(props.message.content) + + const currentConversation = () => { + return $conversationMap()[props.conversationId] + } + const handleCopyMessageItem = () => { + const [Iscopied, copy] = useClipboardCopy(props.message.content) + copy() + setCopied(Iscopied()) + setTimeout(() => setCopied(false), 1000) + } const handleDeleteMessageItem = () => { deleteMessageByConversationId(props.conversationId, props.message) } + const handleRetryMessageItem = () => { + const controller = new AbortController() + globalAbortController.set(controller) + spliceMessageByConversationId(props.conversationId, props.message) + handlePrompt(currentConversation(), '', controller.signal) + // TODO: scrollController seems not working + scrollController().scrollToBottom() + } + + const handleEditMessageItem = () => { + setIsEditing(true) + inputRef.focus() + } + + const handleSend = () => { + if (!inputRef.value) + return + const controller = new AbortController() + const currentMessage: MessageInstance = { + ...props.message, + content: inputPrompt(), + } + + globalAbortController.set(controller) + spliceUpdateMessageByConversationId(props.conversationId, currentMessage) + setIsEditing(false) + handlePrompt(currentConversation(), '', controller.signal) + scrollController().scrollToBottom() + } + const [menuList, setMenuList] = createSignal([ - // TODO: Retry send message - { id: 'retry', label: 'Retry send', icon: 'i-ion:refresh-outline', role: 'all' }, + { id: 'retry', label: 'Retry send', icon: 'i-ion:refresh-outline', role: 'all', action: handleRetryMessageItem }, { id: 'raw', label: 'Show raw code', icon: 'i-carbon-code', role: 'system', action: () => setShowRawCode(!showRawCode()) }, // TODO: Share message // { id: 'share', label: 'Share message', icon: 'i-ion:ios-share-alt' }, - // TODO: Edit message - { id: 'edit', label: 'Edit message', icon: 'i-ion:md-create', role: 'user' }, - { id: 'copy', label: 'Copy message', icon: 'i-carbon-copy', role: 'all', action: copy }, + { id: 'edit', label: 'Edit message', icon: 'i-ion:md-create', role: 'user', action: handleEditMessageItem }, + { id: 'copy', label: 'Copy message', icon: 'i-carbon-copy', role: 'all', action: handleCopyMessageItem }, { id: 'delete', label: 'Delete message', icon: 'i-carbon-trash-can', role: 'all', action: handleDeleteMessageItem }, ]) @@ -45,6 +87,12 @@ export default (props: Props) => { else setMenuList(menuList().filter(item => ['all', 'system'].includes(item.role!))) + const roleClass = { + system: 'bg-gradient-to-b from-gray-300 via-gray-200 to-gray-300', + user: 'bg-gradient-to-b from-gray-300 via-gray-200 to-gray-300', + assistant: 'bg-gradient-to-b from-[#fccb90] to-[#d57eeb]', + } + return (
{ >
- {/* TODO: MessageItem options menu */} -
- {/* +
+
- */} +
-
+
{item => ( @@ -75,17 +122,37 @@ export default (props: Props) => {
- ({ - conversationId: props.conversationId, - messageId: props.message.id || '', - handleStreaming: props.handleStreaming, - }) - : undefined} - showRawCode={showRawCode()} - /> + +