feat: added drag and drop sorting for topics list

This commit is contained in:
kangfenmao 2024-07-10 17:11:59 +08:00
parent cf3ba3c440
commit c9b57536c4
6 changed files with 66 additions and 23 deletions

View File

@ -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 }))
}

View File

@ -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 }
}

View File

@ -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<Props> = ({ activeAssistant, setActiveAssistant, onCreateAssistant }) => {
const { assistants, removeAssistant, updateAssistant, addAssistant, updateAssistants } = useAssistants()
const targetAssistant = useRef<Assistant | null>(null)
@ -73,7 +66,7 @@ const Assistants: FC<Props> = ({ 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<Assistant>(assistants, sourceIndex, destIndex)
updateAssistants(reorderAssistants)
}
}

View File

@ -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<Props> = ({ assistant, activeTopic, setActiveTopic }) => {
const { showRightSidebar } = useShowRightSidebar()
const { removeTopic, updateTopic, removeAllTopics } = useAssistant(assistant.id)
const { removeTopic, updateTopic, removeAllTopics, updateTopics } = useAssistant(assistant.id)
const currentTopic = useRef<Topic | null>(null)
const topicMenuItems: MenuProps['items'] = [
@ -70,6 +72,14 @@ const Topics: FC<Props> = ({ 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<Props> = ({ assistant, activeTopic, setActiveTopic }) => {
</DeleteButton>
</Popconfirm>
</TopicTitle>
{assistant.topics.map((topic) => (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{assistant.topics.map((topic, index) => (
<Draggable key={`draggable_${topic.id}_${index}`} draggableId={topic.id} index={index}>
{(provided) => (
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<Dropdown
menu={{ items: topicMenuItems }}
trigger={['contextMenu']}
key={topic.id}
onOpenChange={(open) => open && (currentTopic.current = topic)}>
<TopicListItem className={topic.id === activeTopic?.id ? 'active' : ''} onClick={() => setActiveTopic(topic)}>
<TopicListItem
className={topic.id === activeTopic?.id ? 'active' : ''}
onClick={() => setActiveTopic(topic)}>
{topic.name}
</TopicListItem>
</Dropdown>
</div>
)}
</Draggable>
))}
</div>
)}
</Droppable>
</DragDropContext>
</Container>
)
}

View File

@ -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

View File

@ -81,3 +81,10 @@ export const getDefaultGroupName = (id: string) => {
return id.toUpperCase()
}
export function droppableReorder<T>(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
}