mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-02 10:29:02 +08:00
fix: add tag collapse state management for assistants (#7436)
Add tag collapse state management for assistants Introduces a collapsedTags state to manage the collapsed/expanded state of tag groups in the assistants list. Updates useTags and AssistantsTab to use this state, and adds actions to toggle and initialize tag collapse in the Redux store.
This commit is contained in:
parent
e2b8133729
commit
1055903456
@ -1,6 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
import { RootState, useAppDispatch, useAppSelector } from '@renderer/store'
|
||||
import { setTagsOrder, updateAssistants } from '@renderer/store/assistants'
|
||||
import { setTagsOrder, updateTagCollapse } from '@renderer/store/assistants'
|
||||
import { flatMap, groupBy, uniq } from 'lodash'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -12,6 +12,8 @@ const selectAssistantsState = (state: RootState) => state.assistants
|
||||
// 记忆化 tagsOrder 选择器(自动处理默认值)--- 这是一个选择器,用于从 store 中获取 tagsOrder 的值。因为之前的tagsOrder是后面新加的,不这样做会报错,所以这里需要处理一下默认值
|
||||
const selectTagsOrder = createSelector([selectAssistantsState], (assistants) => assistants.tagsOrder ?? [])
|
||||
|
||||
const selectCollapsedTags = createSelector([selectAssistantsState], (assistants) => assistants.collapsedTags ?? {})
|
||||
|
||||
// 定义useTags的返回类型,包含所有标签和获取特定标签的助手函数
|
||||
// 为了不增加新的概念,标签直接作为助手的属性,所以这里的标签是指助手的标签属性
|
||||
// 但是为了方便管理,增加了一个获取特定标签的助手函数
|
||||
@ -20,6 +22,7 @@ export const useTags = () => {
|
||||
const { t } = useTranslation()
|
||||
const dispatch = useAppDispatch()
|
||||
const savedTagsOrder = useAppSelector(selectTagsOrder)
|
||||
const collapsedTags = useAppSelector(selectCollapsedTags)
|
||||
|
||||
// 计算所有标签
|
||||
const allTags = useMemo(() => {
|
||||
@ -38,28 +41,6 @@ export const useTags = () => {
|
||||
[assistants]
|
||||
)
|
||||
|
||||
const updateTagsOrder = useCallback(
|
||||
(newOrder: string[]) => {
|
||||
dispatch(setTagsOrder(newOrder))
|
||||
updateAssistants(
|
||||
assistants.map((assistant) => {
|
||||
if (!assistant.tags || assistant.tags.length === 0) {
|
||||
return assistant
|
||||
}
|
||||
const newTags = [...assistant.tags]
|
||||
newTags.sort((a, b) => {
|
||||
return newOrder.indexOf(a) - newOrder.indexOf(b)
|
||||
})
|
||||
return {
|
||||
...assistant,
|
||||
tags: newTags
|
||||
}
|
||||
})
|
||||
)
|
||||
},
|
||||
[assistants, dispatch]
|
||||
)
|
||||
|
||||
const getGroupedAssistants = useMemo(() => {
|
||||
// 按标签分组,处理多标签的情况
|
||||
const assistantsByTags = flatMap(assistants, (assistant) => {
|
||||
@ -100,10 +81,26 @@ export const useTags = () => {
|
||||
return grouped
|
||||
}, [assistants, t, savedTagsOrder])
|
||||
|
||||
const updateTagsOrder = useCallback(
|
||||
(newOrder: string[]) => {
|
||||
dispatch(setTagsOrder(newOrder))
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const toggleTagCollapse = useCallback(
|
||||
(tag: string) => {
|
||||
dispatch(updateTagCollapse(tag))
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
return {
|
||||
allTags,
|
||||
getAssistantsByTag,
|
||||
getGroupedAssistants,
|
||||
updateTagsOrder
|
||||
updateTagsOrder,
|
||||
collapsedTags,
|
||||
toggleTagCollapse
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,10 +27,9 @@ const Assistants: FC<AssistantsTabProps> = ({
|
||||
}) => {
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const [dragging, setDragging] = useState(false)
|
||||
const [collapsedTags, setCollapsedTags] = useState<Record<string, boolean>>({})
|
||||
const { addAgent } = useAgents()
|
||||
const { t } = useTranslation()
|
||||
const { getGroupedAssistants } = useTags()
|
||||
const { getGroupedAssistants, collapsedTags, toggleTagCollapse } = useTags()
|
||||
const { assistantsTabSortType = 'list', setAssistantsTabSortType } = useAssistantsTabSortType()
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
@ -46,13 +45,6 @@ const Assistants: FC<AssistantsTabProps> = ({
|
||||
[activeAssistant, assistants, removeAssistant, setActiveAssistant, onCreateDefaultAssistant]
|
||||
)
|
||||
|
||||
const toggleTagCollapse = useCallback((tag: string) => {
|
||||
setCollapsedTags((prev) => ({
|
||||
...prev,
|
||||
[tag]: !prev[tag]
|
||||
}))
|
||||
}, [])
|
||||
|
||||
const handleSortByChange = useCallback(
|
||||
(sortType: AssistantsSortType) => {
|
||||
setAssistantsTabSortType(sortType)
|
||||
@ -103,7 +95,6 @@ const Assistants: FC<AssistantsTabProps> = ({
|
||||
<DragableList
|
||||
list={group.assistants}
|
||||
onUpdate={(newList) => handleGroupReorder(group.tag, newList)}
|
||||
style={{ paddingBottom: dragging ? '34px' : 0 }}
|
||||
onDragStart={() => setDragging(true)}
|
||||
onDragEnd={() => setDragging(false)}>
|
||||
{(assistant) => (
|
||||
@ -141,7 +132,6 @@ const Assistants: FC<AssistantsTabProps> = ({
|
||||
<DragableList
|
||||
list={assistants}
|
||||
onUpdate={updateAssistants}
|
||||
style={{ paddingBottom: dragging ? '34px' : 0 }}
|
||||
onDragStart={() => setDragging(true)}
|
||||
onDragEnd={() => setDragging(false)}>
|
||||
{(assistant) => (
|
||||
|
||||
@ -9,12 +9,14 @@ export interface AssistantsState {
|
||||
defaultAssistant: Assistant
|
||||
assistants: Assistant[]
|
||||
tagsOrder: string[]
|
||||
collapsedTags: Record<string, boolean>
|
||||
}
|
||||
|
||||
const initialState: AssistantsState = {
|
||||
defaultAssistant: getDefaultAssistant(),
|
||||
assistants: [getDefaultAssistant()],
|
||||
tagsOrder: []
|
||||
tagsOrder: [],
|
||||
collapsedTags: {}
|
||||
}
|
||||
|
||||
const assistantsSlice = createSlice({
|
||||
@ -58,6 +60,26 @@ const assistantsSlice = createSlice({
|
||||
}
|
||||
}
|
||||
},
|
||||
setTagsOrder: (state, action: PayloadAction<string[]>) => {
|
||||
const newOrder = action.payload
|
||||
state.tagsOrder = newOrder
|
||||
const prevCollapsed = state.collapsedTags || {}
|
||||
const updatedCollapsed: Record<string, boolean> = { ...prevCollapsed }
|
||||
newOrder.forEach((tag) => {
|
||||
if (!(tag in updatedCollapsed)) {
|
||||
updatedCollapsed[tag] = false
|
||||
}
|
||||
})
|
||||
state.collapsedTags = updatedCollapsed
|
||||
},
|
||||
updateTagCollapse: (state, action: PayloadAction<string>) => {
|
||||
const tag = action.payload
|
||||
const prev = state.collapsedTags || {}
|
||||
state.collapsedTags = {
|
||||
...prev,
|
||||
[tag]: !prev[tag]
|
||||
}
|
||||
},
|
||||
addTopic: (state, action: PayloadAction<{ assistantId: string; topic: Topic }>) => {
|
||||
const topic = action.payload.topic
|
||||
topic.createdAt = topic.createdAt || new Date().toISOString()
|
||||
@ -130,9 +152,6 @@ const assistantsSlice = createSlice({
|
||||
}
|
||||
: assistant
|
||||
)
|
||||
},
|
||||
setTagsOrder: (state, action: PayloadAction<string[]>) => {
|
||||
state.tagsOrder = action.payload
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -150,7 +169,8 @@ export const {
|
||||
removeAllTopics,
|
||||
setModel,
|
||||
setTagsOrder,
|
||||
updateAssistantSettings
|
||||
updateAssistantSettings,
|
||||
updateTagCollapse
|
||||
} = assistantsSlice.actions
|
||||
|
||||
export default assistantsSlice.reducer
|
||||
|
||||
Loading…
Reference in New Issue
Block a user