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:
自由的世界人 2025-06-24 21:12:49 +08:00 committed by GitHub
parent e2b8133729
commit 1055903456
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 40 deletions

View File

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

View File

@ -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) => (

View File

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