From c9b57536c47a71f100fc5361eafd1788172c34d5 Mon Sep 17 00:00:00 2001 From: kangfenmao Date: Wed, 10 Jul 2024 17:11:59 +0800 Subject: [PATCH] feat: added drag and drop sorting for topics list --- src/renderer/src/hooks/useAssistant.ts | 2 + src/renderer/src/hooks/useTopic.ts | 8 ++- .../src/pages/home/components/Assistants.tsx | 11 +--- .../src/pages/home/components/Topics.tsx | 50 ++++++++++++++----- src/renderer/src/store/assistants.ts | 11 ++++ src/renderer/src/utils/index.ts | 7 +++ 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/renderer/src/hooks/useAssistant.ts b/src/renderer/src/hooks/useAssistant.ts index 68ef89e5..9a6ddc36 100644 --- a/src/renderer/src/hooks/useAssistant.ts +++ b/src/renderer/src/hooks/useAssistant.ts @@ -8,6 +8,7 @@ import { updateAssistants as _updateAssistants, updateDefaultAssistant as _updateDefaultAssistant, updateTopic as _updateTopic, + updateTopics as _updateTopics, addAssistant, removeAssistant, updateAssistant @@ -46,6 +47,7 @@ export function useAssistant(id: string) { addTopic: (topic: Topic) => dispatch(_addTopic({ assistantId: assistant.id, topic })), removeTopic: (topic: Topic) => dispatch(_removeTopic({ assistantId: assistant.id, topic })), updateTopic: (topic: Topic) => dispatch(_updateTopic({ assistantId: assistant.id, topic })), + updateTopics: (topics: Topic[]) => dispatch(_updateTopics({ assistantId: assistant.id, topics })), removeAllTopics: () => dispatch(_removeAllTopics({ assistantId: assistant.id })), setModel: (model: Model) => dispatch(_setModel({ assistantId: assistant.id, model })) } diff --git a/src/renderer/src/hooks/useTopic.ts b/src/renderer/src/hooks/useTopic.ts index e7411958..2dd7d421 100644 --- a/src/renderer/src/hooks/useTopic.ts +++ b/src/renderer/src/hooks/useTopic.ts @@ -1,12 +1,16 @@ import { Assistant } from '@renderer/types' +import { find } from 'lodash' import { useEffect, useState } from 'react' export function useActiveTopic(assistant: Assistant) { const [activeTopic, setActiveTopic] = useState(assistant?.topics[0]) useEffect(() => { - assistant?.topics && setActiveTopic(assistant?.topics[0]) - }, [assistant]) + // activeTopic not in assistant.topics + if (!find(assistant.topics, { id: activeTopic?.id })) { + setActiveTopic(assistant.topics[0]) + } + }, [activeTopic?.id, assistant]) return { activeTopic, setActiveTopic } } diff --git a/src/renderer/src/pages/home/components/Assistants.tsx b/src/renderer/src/pages/home/components/Assistants.tsx index 1533fada..5045a558 100644 --- a/src/renderer/src/pages/home/components/Assistants.tsx +++ b/src/renderer/src/pages/home/components/Assistants.tsx @@ -4,7 +4,7 @@ import AssistantSettingPopup from '@renderer/components/Popups/AssistantSettingP import { useAssistants } from '@renderer/hooks/useAssistant' import { getDefaultTopic } from '@renderer/services/assistant' import { Assistant } from '@renderer/types' -import { uuid } from '@renderer/utils' +import { droppableReorder, uuid } from '@renderer/utils' import { Dropdown, MenuProps } from 'antd' import { last } from 'lodash' import { FC, useRef } from 'react' @@ -16,13 +16,6 @@ interface Props { onCreateAssistant: () => void } -const reorder = (list: Assistant[], startIndex: number, endIndex: number, len = 1) => { - const result = Array.from(list) - const removed = result.splice(startIndex, len) - result.splice(endIndex, 0, ...removed) - return result -} - const Assistants: FC = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => { const { assistants, removeAssistant, updateAssistant, addAssistant, updateAssistants } = useAssistants() const targetAssistant = useRef(null) @@ -73,7 +66,7 @@ const Assistants: FC = ({ activeAssistant, setActiveAssistant, onCreateAs if (result.destination) { const sourceIndex = result.source.index const destIndex = result.destination.index - const reorderAssistants = reorder(assistants, sourceIndex, destIndex) + const reorderAssistants = droppableReorder(assistants, sourceIndex, destIndex) updateAssistants(reorderAssistants) } } diff --git a/src/renderer/src/pages/home/components/Topics.tsx b/src/renderer/src/pages/home/components/Topics.tsx index 6ea259ec..63a309c2 100644 --- a/src/renderer/src/pages/home/components/Topics.tsx +++ b/src/renderer/src/pages/home/components/Topics.tsx @@ -8,6 +8,8 @@ import { FC, useRef } from 'react' import styled from 'styled-components' import { DeleteOutlined, EditOutlined, SignatureOutlined } from '@ant-design/icons' import LocalStorage from '@renderer/services/storage' +import { DragDropContext, Draggable, Droppable, DropResult } from '@hello-pangea/dnd' +import { droppableReorder } from '@renderer/utils' interface Props { assistant: Assistant @@ -17,7 +19,7 @@ interface Props { const Topics: FC = ({ assistant, activeTopic, setActiveTopic }) => { const { showRightSidebar } = useShowRightSidebar() - const { removeTopic, updateTopic, removeAllTopics } = useAssistant(assistant.id) + const { removeTopic, updateTopic, removeAllTopics, updateTopics } = useAssistant(assistant.id) const currentTopic = useRef(null) const topicMenuItems: MenuProps['items'] = [ @@ -70,6 +72,14 @@ const Topics: FC = ({ assistant, activeTopic, setActiveTopic }) => { }) } + const onDragEnd = (result: DropResult) => { + if (result.destination) { + const sourceIndex = result.source.index + const destIndex = result.destination.index + updateTopics(droppableReorder(assistant.topics, sourceIndex, destIndex)) + } + } + if (!showRightSidebar) { return null } @@ -92,17 +102,33 @@ const Topics: FC = ({ assistant, activeTopic, setActiveTopic }) => { - {assistant.topics.map((topic) => ( - open && (currentTopic.current = topic)}> - setActiveTopic(topic)}> - {topic.name} - - - ))} + + + {(provided) => ( +
+ {assistant.topics.map((topic, index) => ( + + {(provided) => ( +
+ open && (currentTopic.current = topic)}> + setActiveTopic(topic)}> + {topic.name} + + +
+ )} +
+ ))} +
+ )} +
+
) } diff --git a/src/renderer/src/store/assistants.ts b/src/renderer/src/store/assistants.ts index f745e7f7..c7d38850 100644 --- a/src/renderer/src/store/assistants.ts +++ b/src/renderer/src/store/assistants.ts @@ -65,6 +65,16 @@ const assistantsSlice = createSlice({ : assistant ) }, + updateTopics: (state, action: PayloadAction<{ assistantId: string; topics: Topic[] }>) => { + state.assistants = state.assistants.map((assistant) => + assistant.id === action.payload.assistantId + ? { + ...assistant, + topics: action.payload.topics + } + : assistant + ) + }, removeAllTopics: (state, action: PayloadAction<{ assistantId: string }>) => { state.assistants = state.assistants.map((assistant) => { if (assistant.id === action.payload.assistantId) { @@ -99,6 +109,7 @@ export const { addTopic, removeTopic, updateTopic, + updateTopics, removeAllTopics, setModel } = assistantsSlice.actions diff --git a/src/renderer/src/utils/index.ts b/src/renderer/src/utils/index.ts index c51e40ef..6064f318 100644 --- a/src/renderer/src/utils/index.ts +++ b/src/renderer/src/utils/index.ts @@ -81,3 +81,10 @@ export const getDefaultGroupName = (id: string) => { return id.toUpperCase() } + +export function droppableReorder(list: T[], startIndex: number, endIndex: number, len = 1) { + const result = Array.from(list) + const removed = result.splice(startIndex, len) + result.splice(endIndex, 0, ...removed) + return result +}