Delete and Update History
This commit is contained in:
		
							parent
							
								
									1c980c4059
								
							
						
					
					
						commit
						f87953ba5c
					
				| @ -11,6 +11,7 @@ | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@ant-design/cssinjs": "^1.18.4", | ||||
|     "@headlessui/react": "^1.7.18", | ||||
|     "@heroicons/react": "^2.1.1", | ||||
|     "@langchain/community": "^0.0.21", | ||||
|     "@langchain/core": "^0.1.22", | ||||
|  | ||||
| @ -9,7 +9,6 @@ export const SettingsOllama = () => { | ||||
|     queryKey: ["fetchOllamURL"], | ||||
|     queryFn: async () => { | ||||
|       const ollamaURL = await getOllamaURL() | ||||
| 
 | ||||
|       return { | ||||
|         ollamaURL | ||||
|       } | ||||
|  | ||||
| @ -1,16 +1,26 @@ | ||||
| import { useQuery } from "@tanstack/react-query" | ||||
| import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" | ||||
| import { | ||||
|   PageAssitDatabase, | ||||
|   formatToChatHistory, | ||||
|   formatToMessage | ||||
|   formatToMessage, | ||||
|   deleteByHistoryId, | ||||
|   updateHistory | ||||
| } from "~libs/db" | ||||
| import { Empty, Skeleton } from "antd" | ||||
| import { Dropdown, Empty, Skeleton, Spin } from "antd" | ||||
| import { useMessageOption } from "~hooks/useMessageOption" | ||||
| import { Trash } from "~icons/Trash" | ||||
| import { Fragment, useState } from "react" | ||||
| import { PencilIcon } from "~icons/PencilIcon" | ||||
| import { EllipsisHorizontalIcon } from "~icons/EllipsisHorizontalIcon" | ||||
| import { Menu, Transition } from "@headlessui/react" | ||||
| 
 | ||||
| type Props = {} | ||||
| 
 | ||||
| export const Sidebar = ({}: Props) => { | ||||
|   const { setMessages, setHistory, setHistoryId } = useMessageOption() | ||||
|   const { setMessages, setHistory, setHistoryId, historyId, clearChat } = | ||||
|     useMessageOption() | ||||
|   const [processingId, setProcessingId] = useState<string>("") | ||||
|   const client = useQueryClient() | ||||
| 
 | ||||
|   const { data: chatHistories, status } = useQuery({ | ||||
|     queryKey: ["fetchChatHistory"], | ||||
| @ -21,8 +31,35 @@ export const Sidebar = ({}: Props) => { | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   const { isPending: isDeleting, mutate: deleteHistory } = useMutation({ | ||||
|     mutationKey: ["deleteHistory"], | ||||
|     mutationFn: deleteByHistoryId, | ||||
|     onSuccess: (history_id) => { | ||||
|       client.invalidateQueries({ | ||||
|         queryKey: ["fetchChatHistory"] | ||||
|       }) | ||||
|       setProcessingId("") | ||||
|       if (historyId === history_id) { | ||||
|         clearChat() | ||||
|       } | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   const { isPending: isEditing, mutate: editHistory } = useMutation({ | ||||
|     mutationKey: ["editHistory"], | ||||
|     mutationFn: async (data: { id: string; title: string }) => { | ||||
|       return await updateHistory(data.id, data.title) | ||||
|     }, | ||||
|     onSuccess: () => { | ||||
|       client.invalidateQueries({ | ||||
|         queryKey: ["fetchChatHistory"] | ||||
|       }) | ||||
|       setProcessingId("") | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="overflow-y-auto"> | ||||
|     <div className="overflow-y-auto z-99"> | ||||
|       {status === "success" && chatHistories.length === 0 && ( | ||||
|         <div className="flex justify-center items-center mt-20 overflow-hidden"> | ||||
|           <Empty description="No history yet" /> | ||||
| @ -41,18 +78,49 @@ export const Sidebar = ({}: Props) => { | ||||
|       {status === "success" && chatHistories.length > 0 && ( | ||||
|         <div className="flex flex-col gap-2"> | ||||
|           {chatHistories.map((chat, index) => ( | ||||
|             <button | ||||
|               onClick={async () => { | ||||
|                 const db = new PageAssitDatabase() | ||||
|                 const history = await db.getChatHistory(chat.id) | ||||
|                 setHistoryId(chat.id) | ||||
|                 setHistory(formatToChatHistory(history)) | ||||
|                 setMessages(formatToMessage(history)) | ||||
|               }} | ||||
|             <div | ||||
|               key={index} | ||||
|               className="flex text-start py-2 px-2 cursor-pointer items-start gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out  bg-gray-100 dark:bg-[#232222] dark:text-gray-100 text-gray-800 border hover:bg-gray-200 dark:hover:bg-[#2d2d2d] dark:border-gray-800"> | ||||
|               <span className="flex-grow truncate">{chat.title}</span> | ||||
|             </button> | ||||
|               className="flex py-2 px-2 items-start gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out   bg-gray-100 dark:bg-[#232222] dark:text-gray-100 text-gray-800 border hover:bg-gray-200 dark:hover:bg-[#2d2d2d] dark:border-gray-800"> | ||||
|               <button | ||||
|                 className="flex-1 overflow-hidden break-all text-start truncate w-full" | ||||
|                 onClick={async () => { | ||||
|                   const db = new PageAssitDatabase() | ||||
|                   const history = await db.getChatHistory(chat.id) | ||||
|                   setHistoryId(chat.id) | ||||
|                   setHistory(formatToChatHistory(history)) | ||||
|                   setMessages(formatToMessage(history)) | ||||
|                 }}> | ||||
|                 <span className="flex-grow truncate">{chat.title}</span> | ||||
|               </button> | ||||
|               <div className="flex flex-row gap-3"> | ||||
|                 <button | ||||
|                   onClick={() => { | ||||
|                     const newTitle = prompt("Enter new title", chat.title) | ||||
| 
 | ||||
|                     if (newTitle) { | ||||
|                       editHistory({ id: chat.id, title: newTitle }) | ||||
|                     } | ||||
| 
 | ||||
|                     setProcessingId(chat.id) | ||||
|                   }} | ||||
|                   className="text-gray-500 dark:text-gray-400 opacity-80"> | ||||
|                   <PencilIcon className="w-4 h-4" /> | ||||
|                 </button> | ||||
| 
 | ||||
|                 <button | ||||
|                   onClick={() => { | ||||
|                     if ( | ||||
|                       !confirm("Are you sure you want to delete this history?") | ||||
|                     ) | ||||
|                       return | ||||
|                     deleteHistory(chat.id) | ||||
|                     setProcessingId(chat.id) | ||||
|                   }} | ||||
|                   className="text-red-500 dark:text-red-400 opacity-80"> | ||||
|                   <Trash className=" w-4 h-4 " /> | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|           ))} | ||||
|         </div> | ||||
|       )} | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/icons/EllipsisHorizontalIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/icons/EllipsisHorizontalIcon.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| type Props = { | ||||
|     className: string | ||||
| } | ||||
| 
 | ||||
| export const EllipsisHorizontalIcon = ({ className }: Props) => { | ||||
|     return   <svg | ||||
|     xmlns="http://www.w3.org/2000/svg" | ||||
|     fill="none" | ||||
|     stroke="currentColor" | ||||
|     strokeLinecap="round" | ||||
|     strokeLinejoin="round" | ||||
|     strokeWidth="2" | ||||
|     viewBox="0 0 24 24" | ||||
|     className={className} | ||||
|   > | ||||
|     <circle cx="12" cy="12" r="1"></circle> | ||||
|     <circle cx="12" cy="5" r="1"></circle> | ||||
|     <circle cx="12" cy="19" r="1"></circle> | ||||
|   </svg> | ||||
| } | ||||
							
								
								
									
										19
									
								
								src/icons/PencilIcon.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/icons/PencilIcon.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| type Props = { | ||||
|   className: string | ||||
| } | ||||
| 
 | ||||
| export const PencilIcon = ({ className }: Props) => { | ||||
|   return ( | ||||
|     <svg | ||||
|       xmlns="http://www.w3.org/2000/svg" | ||||
|       fill="none" | ||||
|       stroke="currentColor" | ||||
|       strokeLinecap="round" | ||||
|       strokeLinejoin="round" | ||||
|       strokeWidth="2" | ||||
|       viewBox="0 0 24 24" | ||||
|       className={className}> | ||||
|       <path d="M17 3a2.85 2.83 0 114 4L7.5 20.5 2 22l1.5-5.5zM15 5l4 4"></path> | ||||
|     </svg> | ||||
|   ) | ||||
| } | ||||
| @ -87,6 +87,10 @@ export class PageAssitDatabase { | ||||
|     } | ||||
|     this.db.remove("chatHistories") | ||||
|   } | ||||
| 
 | ||||
|   async deleteMessage(history_id: string) { | ||||
|     await this.db.remove(history_id) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const generateID = () => { | ||||
| @ -145,3 +149,22 @@ export const formatToMessage = (messages: MessageHistory): MessageType[] => { | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| export const deleteByHistoryId = async (history_id: string) => { | ||||
|   const db = new PageAssitDatabase() | ||||
|   await db.deleteMessage(history_id) | ||||
|   await db.removeChatHistory(history_id) | ||||
|   return history_id | ||||
| } | ||||
| 
 | ||||
| export const updateHistory = async (id: string, title: string) => { | ||||
|   const db = new PageAssitDatabase() | ||||
|   const chatHistories = await db.getChatHistories() | ||||
|   const newChatHistories = chatHistories.map((history) => { | ||||
|     if (history.id === id) { | ||||
|       history.title = title | ||||
|     } | ||||
|     return history | ||||
|   }) | ||||
|   db.db.set({ chatHistories: newChatHistories }) | ||||
| } | ||||
|  | ||||
							
								
								
									
										25
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								yarn.lock
									
									
									
									
									
								
							| @ -456,6 +456,14 @@ | ||||
|   dependencies: | ||||
|     cross-spawn "^7.0.3" | ||||
| 
 | ||||
| "@headlessui/react@^1.7.18": | ||||
|   version "1.7.18" | ||||
|   resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.18.tgz#30af4634d2215b2ca1aa29d07f33d02bea82d9d7" | ||||
|   integrity sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ== | ||||
|   dependencies: | ||||
|     "@tanstack/react-virtual" "^3.0.0-beta.60" | ||||
|     client-only "^0.0.1" | ||||
| 
 | ||||
| "@heroicons/react@^2.1.1": | ||||
|   version "2.1.1" | ||||
|   resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.1.1.tgz#422deb80c4d6caf3371aec6f4bee8361a354dc13" | ||||
| @ -2306,6 +2314,18 @@ | ||||
|   dependencies: | ||||
|     "@tanstack/query-core" "5.18.0" | ||||
| 
 | ||||
| "@tanstack/react-virtual@^3.0.0-beta.60": | ||||
|   version "3.1.2" | ||||
|   resolved "https://registry.yarnpkg.com/@tanstack/react-virtual/-/react-virtual-3.1.2.tgz#eb62b73cc82e34860604cd3d682a17db590f3c45" | ||||
|   integrity sha512-qibmxtctgOZo2I+3Rw5GR9kXgaa15U5r3/idDY1ItUKW15UK7GhCfyIfE6qYuJ1fxQF6dJDsD8SbpPyuJgpxuA== | ||||
|   dependencies: | ||||
|     "@tanstack/virtual-core" "3.1.2" | ||||
| 
 | ||||
| "@tanstack/virtual-core@3.1.2": | ||||
|   version "3.1.2" | ||||
|   resolved "https://registry.yarnpkg.com/@tanstack/virtual-core/-/virtual-core-3.1.2.tgz#ca76f28f826fbd3310f88c3cd355d9c4aba80abb" | ||||
|   integrity sha512-DATZJs8iejkIUqXZe6ruDAnjFo78BKnIIgqQZrc7CmEFqfLEN/TPD91n4hRfo6hpRB6xC00bwKxv7vdjFNEmOg== | ||||
| 
 | ||||
| "@tootallnate/once@2": | ||||
|   version "2.0.0" | ||||
|   resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" | ||||
| @ -3078,6 +3098,11 @@ cli-width@^4.1.0: | ||||
|   resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" | ||||
|   integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== | ||||
| 
 | ||||
| client-only@^0.0.1: | ||||
|   version "0.0.1" | ||||
|   resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" | ||||
|   integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== | ||||
| 
 | ||||
| clone@^1.0.2: | ||||
|   version "1.0.4" | ||||
|   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user