refactor: Rename AssistantItemComponent to AssistantItem and update imports
This commit is contained in:
parent
fc59144b1d
commit
fb6b0b0c97
186
src/renderer/src/pages/home/Tabs/AssistantItem.tsx
Normal file
186
src/renderer/src/pages/home/Tabs/AssistantItem.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { DeleteOutlined, EditOutlined, MinusCircleOutlined, SaveOutlined } from '@ant-design/icons'
|
||||
import CopyIcon from '@renderer/components/Icons/CopyIcon'
|
||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||
import { modelGenerating } from '@renderer/hooks/useRuntime'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
||||
import { getDefaultTopic } from '@renderer/services/AssistantService'
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { uuid } from '@renderer/utils'
|
||||
import { Dropdown } from 'antd'
|
||||
import { ItemType } from 'antd/es/menu/interface'
|
||||
import { omit } from 'lodash'
|
||||
import { FC, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface AssistantItemProps {
|
||||
assistant: Assistant
|
||||
isActive: boolean
|
||||
onSwitch: (assistant: Assistant) => void
|
||||
onDelete: (assistant: Assistant) => void
|
||||
onCreateDefaultAssistant: () => void
|
||||
addAgent: (agent: any) => void
|
||||
addAssistant: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const AssistantItem: FC<AssistantItemProps> = ({ assistant, isActive, onSwitch, onDelete, addAgent, addAssistant }) => {
|
||||
const { t } = useTranslation()
|
||||
const { removeAllTopics } = useAssistant(assistant.id) // 使用当前助手的ID
|
||||
const { clickAssistantToShowTopic, topicPosition } = useSettings()
|
||||
|
||||
const getMenuItems = useCallback(
|
||||
(assistant: Assistant): ItemType[] => [
|
||||
{
|
||||
label: t('assistants.edit.title'),
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
onClick: () => AssistantSettingsPopup.show({ assistant })
|
||||
},
|
||||
{
|
||||
label: t('assistants.copy.title'),
|
||||
key: 'duplicate',
|
||||
icon: <CopyIcon />,
|
||||
onClick: async () => {
|
||||
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic(assistant.id)] }
|
||||
addAssistant(_assistant)
|
||||
onSwitch(_assistant)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('assistants.clear.title'),
|
||||
key: 'clear',
|
||||
icon: <MinusCircleOutlined />,
|
||||
onClick: () => {
|
||||
window.modal.confirm({
|
||||
title: t('assistants.clear.title'),
|
||||
content: t('assistants.clear.content'),
|
||||
centered: true,
|
||||
okButtonProps: { danger: true },
|
||||
onOk: () => removeAllTopics() // 使用当前助手的removeAllTopics
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('assistants.save.title'),
|
||||
key: 'save-to-agent',
|
||||
icon: <SaveOutlined />,
|
||||
onClick: async () => {
|
||||
const agent = omit(assistant, ['model', 'emoji'])
|
||||
agent.id = uuid()
|
||||
agent.type = 'agent'
|
||||
addAgent(agent)
|
||||
window.message.success({
|
||||
content: t('assistants.save.success'),
|
||||
key: 'save-to-agent'
|
||||
})
|
||||
}
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
label: t('common.delete'),
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
onClick: () => {
|
||||
window.modal.confirm({
|
||||
title: t('assistants.delete.title'),
|
||||
content: t('assistants.delete.content'),
|
||||
centered: true,
|
||||
okButtonProps: { danger: true },
|
||||
onOk: () => onDelete(assistant)
|
||||
})
|
||||
}
|
||||
}
|
||||
],
|
||||
[addAgent, addAssistant, onSwitch, removeAllTopics, t, onDelete]
|
||||
)
|
||||
|
||||
const handleSwitch = useCallback(async () => {
|
||||
await modelGenerating()
|
||||
|
||||
if (topicPosition === 'left' && clickAssistantToShowTopic) {
|
||||
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
|
||||
}
|
||||
|
||||
onSwitch(assistant)
|
||||
}, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition])
|
||||
|
||||
return (
|
||||
<Dropdown menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}>
|
||||
<Container onClick={handleSwitch} className={isActive ? 'active' : ''}>
|
||||
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
|
||||
{isActive && (
|
||||
<MenuButton onClick={() => EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)}>
|
||||
<TopicCount className="topics-count">{assistant.topics.length}</TopicCount>
|
||||
</MenuButton>
|
||||
)}
|
||||
</Container>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 7px 12px;
|
||||
position: relative;
|
||||
margin: 0 10px;
|
||||
padding-right: 35px;
|
||||
font-family: Ubuntu;
|
||||
border-radius: var(--list-item-border-radius);
|
||||
border: 0.5px solid transparent;
|
||||
cursor: pointer;
|
||||
.iconfont {
|
||||
opacity: 0;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
&.active {
|
||||
background-color: var(--color-background-soft);
|
||||
border: 0.5px solid var(--color-border);
|
||||
.name {
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const AssistantName = styled.div`
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
`
|
||||
|
||||
const MenuButton = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
min-height: 22px;
|
||||
border-radius: 11px;
|
||||
position: absolute;
|
||||
background-color: var(--color-background);
|
||||
right: 9px;
|
||||
top: 6px;
|
||||
`
|
||||
|
||||
const TopicCount = styled.div`
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
export default AssistantItem
|
||||
@ -1,197 +0,0 @@
|
||||
import CopyIcon from "@renderer/components/Icons/CopyIcon"
|
||||
import { useAssistant } from "@renderer/hooks/useAssistant"
|
||||
import { modelGenerating } from "@renderer/hooks/useRuntime"
|
||||
import { useSettings } from "@renderer/hooks/useSettings"
|
||||
import AssistantSettingsPopup from "@renderer/pages/settings/AssistantSettings"
|
||||
import { getDefaultTopic } from "@renderer/services/AssistantService"
|
||||
|
||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||
import { Assistant } from "@renderer/types"
|
||||
import { uuid } from "@renderer/utils"
|
||||
import { Dropdown } from "antd"
|
||||
import { ItemType } from "antd/es/menu/interface"
|
||||
import { omit } from "lodash"
|
||||
import { FC, useCallback } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { DeleteOutlined, EditOutlined, MinusCircleOutlined, SaveOutlined } from '@ant-design/icons'
|
||||
|
||||
import styled from "styled-components"
|
||||
|
||||
interface AssistantItemProps {
|
||||
assistant: Assistant
|
||||
isActive: boolean
|
||||
onSwitch: (assistant: Assistant) => void
|
||||
onDelete: (assistant: Assistant) => void
|
||||
onCreateDefaultAssistant: () => void
|
||||
addAgent: (agent: any) => void
|
||||
addAssistant: (assistant: Assistant) => void
|
||||
}
|
||||
|
||||
const AssistantItemComponent: FC<AssistantItemProps> = ({
|
||||
assistant,
|
||||
isActive,
|
||||
onSwitch,
|
||||
onDelete,
|
||||
addAgent,
|
||||
addAssistant
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { removeAllTopics } = useAssistant(assistant.id) // 使用当前助手的ID
|
||||
const { clickAssistantToShowTopic, topicPosition } = useSettings()
|
||||
|
||||
const getMenuItems = useCallback(
|
||||
(assistant: Assistant): ItemType[] => [
|
||||
{
|
||||
label: t('assistants.edit.title'),
|
||||
key: 'edit',
|
||||
icon: <EditOutlined />,
|
||||
onClick: () => AssistantSettingsPopup.show({ assistant })
|
||||
},
|
||||
{
|
||||
label: t('assistants.copy.title'),
|
||||
key: 'duplicate',
|
||||
icon: <CopyIcon />,
|
||||
onClick: async () => {
|
||||
const _assistant: Assistant = { ...assistant, id: uuid(), topics: [getDefaultTopic(assistant.id)] }
|
||||
addAssistant(_assistant)
|
||||
onSwitch(_assistant)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('assistants.clear.title'),
|
||||
key: 'clear',
|
||||
icon: <MinusCircleOutlined />,
|
||||
onClick: () => {
|
||||
window.modal.confirm({
|
||||
title: t('assistants.clear.title'),
|
||||
content: t('assistants.clear.content'),
|
||||
centered: true,
|
||||
okButtonProps: { danger: true },
|
||||
onOk: () => removeAllTopics() // 使用当前助手的removeAllTopics
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
label: t('assistants.save.title'),
|
||||
key: 'save-to-agent',
|
||||
icon: <SaveOutlined />,
|
||||
onClick: async () => {
|
||||
const agent = omit(assistant, ['model', 'emoji'])
|
||||
agent.id = uuid()
|
||||
agent.type = 'agent'
|
||||
addAgent(agent)
|
||||
window.message.success({
|
||||
content: t('assistants.save.success'),
|
||||
key: 'save-to-agent'
|
||||
})
|
||||
}
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
label: t('common.delete'),
|
||||
key: 'delete',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
onClick: () => {
|
||||
window.modal.confirm({
|
||||
title: t('assistants.delete.title'),
|
||||
content: t('assistants.delete.content'),
|
||||
centered: true,
|
||||
okButtonProps: { danger: true },
|
||||
onOk: () => onDelete(assistant)
|
||||
})
|
||||
}
|
||||
}
|
||||
],
|
||||
[addAgent, addAssistant, onSwitch, removeAllTopics, t, onDelete]
|
||||
)
|
||||
|
||||
const handleSwitch = useCallback(async () => {
|
||||
await modelGenerating()
|
||||
|
||||
if (topicPosition === 'left' && clickAssistantToShowTopic) {
|
||||
EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)
|
||||
}
|
||||
|
||||
onSwitch(assistant)
|
||||
}, [clickAssistantToShowTopic, onSwitch, assistant, topicPosition])
|
||||
|
||||
return (
|
||||
<Dropdown menu={{ items: getMenuItems(assistant) }} trigger={['contextMenu']}>
|
||||
<AssistantItem onClick={handleSwitch} className={isActive ? 'active' : ''}>
|
||||
<AssistantName className="name">{assistant.name || t('chat.default.name')}</AssistantName>
|
||||
{isActive && (
|
||||
<MenuButton onClick={() => EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)}>
|
||||
<TopicCount className="topics-count">{assistant.topics.length}</TopicCount>
|
||||
</MenuButton>
|
||||
)}
|
||||
</AssistantItem>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
export default AssistantItemComponent // 使用默认导出
|
||||
|
||||
|
||||
|
||||
|
||||
const AssistantItem = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 7px 12px;
|
||||
position: relative;
|
||||
margin: 0 10px;
|
||||
padding-right: 35px;
|
||||
font-family: Ubuntu;
|
||||
border-radius: var(--list-item-border-radius);
|
||||
border: 0.5px solid transparent;
|
||||
cursor: pointer;
|
||||
.iconfont {
|
||||
opacity: 0;
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
&:hover {
|
||||
background-color: var(--color-background-soft);
|
||||
}
|
||||
&.active {
|
||||
background-color: var(--color-background-soft);
|
||||
border: 0.5px solid var(--color-border);
|
||||
.name {
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const AssistantName = styled.div`
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
font-size: 13px;
|
||||
`
|
||||
|
||||
const MenuButton = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-width: 22px;
|
||||
height: 22px;
|
||||
min-width: 22px;
|
||||
min-height: 22px;
|
||||
border-radius: 11px;
|
||||
position: absolute;
|
||||
background-color: var(--color-background);
|
||||
right: 9px;
|
||||
top: 6px;
|
||||
`
|
||||
|
||||
const TopicCount = styled.div`
|
||||
color: var(--color-text);
|
||||
font-size: 10px;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`
|
||||
@ -1,22 +1,77 @@
|
||||
import { useCallback, useState, FC } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { PlusOutlined } from '@ant-design/icons'
|
||||
import DragableList from "@renderer/components/DragableList"
|
||||
import Scrollbar from "@renderer/components/Scrollbar"
|
||||
import { useAgents } from "@renderer/hooks/useAgents"
|
||||
import { useAssistants } from "@renderer/hooks/useAssistant"
|
||||
import { Assistant } from "@renderer/types"
|
||||
import styled from "styled-components"
|
||||
import AssistantItemComponent from "@renderer/pages/home/Tabs/AssistantItemComponent"
|
||||
import DragableList from '@renderer/components/DragableList'
|
||||
import Scrollbar from '@renderer/components/Scrollbar'
|
||||
import { useAgents } from '@renderer/hooks/useAgents'
|
||||
import { useAssistants } from '@renderer/hooks/useAssistant'
|
||||
import { Assistant } from '@renderer/types'
|
||||
import { FC, useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
// 类型定义
|
||||
interface AssistantsProps {
|
||||
import AssistantItem from './AssistantItem'
|
||||
|
||||
interface AssistantsTabProps {
|
||||
activeAssistant: Assistant
|
||||
setActiveAssistant: (assistant: Assistant) => void
|
||||
onCreateAssistant: () => void
|
||||
onCreateDefaultAssistant: () => void
|
||||
}
|
||||
|
||||
const Assistants: FC<AssistantsTabProps> = ({
|
||||
activeAssistant,
|
||||
setActiveAssistant,
|
||||
onCreateAssistant,
|
||||
onCreateDefaultAssistant
|
||||
}) => {
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const [dragging, setDragging] = useState(false)
|
||||
const { addAgent } = useAgents()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const onDelete = useCallback(
|
||||
(assistant: Assistant) => {
|
||||
const remaining = assistants.filter((a) => a.id !== assistant.id)
|
||||
const newActive = remaining[remaining.length - 1]
|
||||
newActive ? setActiveAssistant(newActive) : onCreateDefaultAssistant()
|
||||
removeAssistant(assistant.id)
|
||||
},
|
||||
[assistants, removeAssistant, setActiveAssistant, onCreateDefaultAssistant]
|
||||
)
|
||||
|
||||
return (
|
||||
<Container className="assistants-tab">
|
||||
<DragableList
|
||||
list={assistants}
|
||||
onUpdate={updateAssistants}
|
||||
style={{ paddingBottom: dragging ? '34px' : 0 }}
|
||||
onDragStart={() => setDragging(true)}
|
||||
onDragEnd={() => setDragging(false)}>
|
||||
{(assistant) => (
|
||||
<AssistantItem
|
||||
key={assistant.id}
|
||||
assistant={assistant}
|
||||
isActive={assistant.id === activeAssistant.id}
|
||||
onSwitch={setActiveAssistant}
|
||||
onDelete={onDelete}
|
||||
addAgent={addAgent}
|
||||
addAssistant={addAssistant}
|
||||
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
||||
/>
|
||||
)}
|
||||
</DragableList>
|
||||
{!dragging && (
|
||||
<AssistantAddItem onClick={onCreateAssistant}>
|
||||
<AssistantName>
|
||||
<PlusOutlined style={{ color: 'var(--color-text-2)', marginRight: 4 }} />
|
||||
{t('chat.add.assistant.title')}
|
||||
</AssistantName>
|
||||
</AssistantAddItem>
|
||||
)}
|
||||
<div style={{ minHeight: 10 }}></div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
// 样式组件(只定义一次)
|
||||
const Container = styled(Scrollbar)`
|
||||
display: flex;
|
||||
@ -25,7 +80,7 @@ const Container = styled(Scrollbar)`
|
||||
user-select: none;
|
||||
`
|
||||
|
||||
const AssistantItem = styled.div`
|
||||
const AssistantAddItem = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@ -57,60 +112,4 @@ const AssistantName = styled.div`
|
||||
font-size: 13px;
|
||||
`
|
||||
|
||||
const Assistants: FC<AssistantsProps> = ({
|
||||
activeAssistant,
|
||||
setActiveAssistant,
|
||||
onCreateAssistant,
|
||||
onCreateDefaultAssistant
|
||||
}) => {
|
||||
const { assistants, removeAssistant, addAssistant, updateAssistants } = useAssistants()
|
||||
const [dragging, setDragging] = useState(false)
|
||||
const { addAgent } = useAgents()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const onDelete = useCallback(
|
||||
(assistant: Assistant) => {
|
||||
const remaining = assistants.filter(a => a.id !== assistant.id)
|
||||
const newActive = remaining[remaining.length - 1]
|
||||
newActive ? setActiveAssistant(newActive) : onCreateDefaultAssistant()
|
||||
removeAssistant(assistant.id)
|
||||
},
|
||||
[assistants, removeAssistant, setActiveAssistant, onCreateDefaultAssistant]
|
||||
)
|
||||
|
||||
return (
|
||||
<Container className="assistants-tab">
|
||||
<DragableList
|
||||
list={assistants}
|
||||
onUpdate={updateAssistants}
|
||||
style={{ paddingBottom: dragging ? '34px' : 0 }}
|
||||
onDragStart={() => setDragging(true)}
|
||||
onDragEnd={() => setDragging(false)}
|
||||
>
|
||||
{(assistant) => (
|
||||
<AssistantItemComponent
|
||||
key={assistant.id}
|
||||
assistant={assistant}
|
||||
isActive={assistant.id === activeAssistant.id}
|
||||
onSwitch={setActiveAssistant}
|
||||
onDelete={onDelete}
|
||||
addAgent={addAgent}
|
||||
addAssistant={addAssistant}
|
||||
onCreateDefaultAssistant={onCreateDefaultAssistant}
|
||||
/>
|
||||
)}
|
||||
</DragableList>
|
||||
{!dragging && (
|
||||
<AssistantItem onClick={onCreateAssistant}>
|
||||
<AssistantName>
|
||||
<PlusOutlined style={{ color: 'var(--color-text-2)', marginRight: 4 }} />
|
||||
{t('chat.add.assistant.title')}
|
||||
</AssistantName>
|
||||
</AssistantItem>
|
||||
)}
|
||||
<div style={{ minHeight: 10 }}></div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default Assistants
|
||||
|
||||
@ -214,4 +214,4 @@ export const exportMarkdownToNotion = async (title: string, content: string) =>
|
||||
isExporting: false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user