mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-19 14:41:24 +08:00
refactor(ui): improve settings tab and assistant item UI (#11819)
* refactor(ui): improve settings tab and assistant item UI - Remove SettingsTab from HomeTabs, open settings via navbar drawer instead - Add menu icon to assistant/agent items for quick access to settings popup - Remove SessionSettingsTab component (consolidated into settings popup) - Restore avatar display in bubble message style - Update topic/session item styles for consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor(ui): simplify MessageHeader component logic - Removed unnecessary header visibility check in MessageHeader. - Updated justifyContent logic for UserWrap to account for multi-select mode. This change enhances the clarity and maintainability of the MessageHeader component. * refactor(ui): streamline ChatNavbar and SettingsTab components - Removed unused chat state from ChatNavbar. - Updated SettingsTab to conditionally render settings based on active topic or session. - Enhanced clarity and maintainability by reducing unnecessary checks and improving component logic. This change improves the overall user experience and code readability. * refactor(ui): enhance AgentItem and ChatNavbar components for improved UI - Updated AgentItem to conditionally hide the assistant icon based on settings. - Enhanced ChatNavbar to display the assistant's emoji and name with a new layout. - Introduced memoization for assistant name to optimize rendering. These changes improve the user interface and maintainability of the components. * refactor(ui): update HtmlArtifactsPopup to start in fullscreen mode - Changed initial state of isFullscreen in HtmlArtifactsPopup from false to true. This adjustment enhances the user experience by providing a more immersive view upon opening the popup. * refactor(types): remove 'settings' tab from Tab type - Updated the Tab type in chat.ts to remove the 'settings' option, simplifying the available tabs for the chat interface. This change streamlines the chat functionality and improves code clarity. * refactor(ui): enhance UserWrap styling in MessageHeader component - Added flex property to UserWrap to improve layout flexibility. This change enhances the responsiveness and layout management of the MessageHeader component. * refactor(ui): update HtmlArtifactsPopup to prevent drag on ViewControls - Added "nodrag" class to ViewControls to prevent drag events on double click. This change improves the user interaction by ensuring that double-clicking on the ViewControls does not trigger drag actions. * refactor(ui): adjust spacing in AgentLabel component - Updated the gap between items in the AgentLabel component from 1 to 2 for improved layout consistency. This change enhances the visual spacing and overall user interface of the AgentSettings page. * refactor(ui): remove unused useSessions hook from AgentItem component - Eliminated the useSessions hook from the AgentItem component to streamline the code and improve performance. This change enhances the maintainability of the AgentItem component by removing unnecessary dependencies. * refactor(ui): optimize MessageHeader component layout and logic - Introduced a memoized userNameJustifyContent calculation to streamline the justifyContent logic for UserWrap. - Simplified the HStack component by replacing inline logic with the new memoized value. These changes enhance the maintainability and clarity of the MessageHeader component. --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
5f3af646f4
commit
367c4fe6b6
@ -25,7 +25,7 @@ type ViewMode = 'split' | 'code' | 'preview'
|
|||||||
const HtmlArtifactsPopup: React.FC<HtmlArtifactsPopupProps> = ({ open, title, html, onSave, onClose }) => {
|
const HtmlArtifactsPopup: React.FC<HtmlArtifactsPopupProps> = ({ open, title, html, onSave, onClose }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [viewMode, setViewMode] = useState<ViewMode>('split')
|
const [viewMode, setViewMode] = useState<ViewMode>('split')
|
||||||
const [isFullscreen, setIsFullscreen] = useState(false)
|
const [isFullscreen, setIsFullscreen] = useState(true)
|
||||||
const [saved, setSaved] = useTemporaryValue(false, 2000)
|
const [saved, setSaved] = useTemporaryValue(false, 2000)
|
||||||
const codeEditorRef = useRef<CodeEditorHandles>(null)
|
const codeEditorRef = useRef<CodeEditorHandles>(null)
|
||||||
const previewFrameRef = useRef<HTMLIFrameElement>(null)
|
const previewFrameRef = useRef<HTMLIFrameElement>(null)
|
||||||
@ -78,7 +78,7 @@ const HtmlArtifactsPopup: React.FC<HtmlArtifactsPopupProps> = ({ open, title, ht
|
|||||||
</HeaderLeft>
|
</HeaderLeft>
|
||||||
|
|
||||||
<HeaderCenter>
|
<HeaderCenter>
|
||||||
<ViewControls onDoubleClick={(e) => e.stopPropagation()}>
|
<ViewControls onDoubleClick={(e) => e.stopPropagation()} className="nodrag">
|
||||||
<ViewButton
|
<ViewButton
|
||||||
size="small"
|
size="small"
|
||||||
type={viewMode === 'split' ? 'primary' : 'default'}
|
type={viewMode === 'split' ? 'primary' : 'default'}
|
||||||
|
|||||||
@ -89,10 +89,7 @@ const Sidebar: FC = () => {
|
|||||||
)}
|
)}
|
||||||
</MainMenusContainer>
|
</MainMenusContainer>
|
||||||
<Menus>
|
<Menus>
|
||||||
<Tooltip
|
<Tooltip title={t('settings.theme.title') + ': ' + getThemeModeLabel(settedTheme)} placement="right">
|
||||||
title={t('settings.theme.title') + ': ' + getThemeModeLabel(settedTheme)}
|
|
||||||
mouseEnterDelay={0.8}
|
|
||||||
placement="right">
|
|
||||||
<Icon theme={theme} onClick={toggleTheme}>
|
<Icon theme={theme} onClick={toggleTheme}>
|
||||||
{settedTheme === ThemeMode.dark ? (
|
{settedTheme === ThemeMode.dark ? (
|
||||||
<Moon size={20} className="icon" />
|
<Moon size={20} className="icon" />
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import AssistantsDrawer from './components/AssistantsDrawer'
|
import AssistantsDrawer from './components/AssistantsDrawer'
|
||||||
import ChatNavbarContent from './components/ChatNavbarContent'
|
import ChatNavbarContent from './components/ChatNavbarContent'
|
||||||
|
import SettingsButton from './components/SettingsButton'
|
||||||
import UpdateAppButton from './components/UpdateAppButton'
|
import UpdateAppButton from './components/UpdateAppButton'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -65,14 +66,6 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleUpdateModel = useCallback(
|
|
||||||
// async (model: ApiModel) => {
|
|
||||||
// if (!activeSession || !activeAgent) return
|
|
||||||
// return updateModel(activeSession.id, model.id, { showSuccessToast: false })
|
|
||||||
// },
|
|
||||||
// [activeAgent, activeSession, updateModel]
|
|
||||||
// )
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavbarHeader className="home-navbar" style={{ height: 'var(--navbar-height)' }}>
|
<NavbarHeader className="home-navbar" style={{ height: 'var(--navbar-height)' }}>
|
||||||
<div className="flex h-full min-w-0 flex-1 shrink items-center overflow-auto">
|
<div className="flex h-full min-w-0 flex-1 shrink items-center overflow-auto">
|
||||||
@ -107,6 +100,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTo
|
|||||||
</div>
|
</div>
|
||||||
<HStack alignItems="center" gap={8}>
|
<HStack alignItems="center" gap={8}>
|
||||||
{isTopNavbar && <UpdateAppButton />}
|
{isTopNavbar && <UpdateAppButton />}
|
||||||
|
<SettingsButton assistant={assistant} />
|
||||||
{isTopNavbar && (
|
{isTopNavbar && (
|
||||||
<Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}>
|
<Tooltip title={t('navbar.expand')} mouseEnterDelay={0.8}>
|
||||||
<NarrowIcon onClick={handleNarrowModeToggle}>
|
<NarrowIcon onClick={handleNarrowModeToggle}>
|
||||||
|
|||||||
@ -429,7 +429,7 @@ const FileBlocksContainer = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 0 15px;
|
padding: 0;
|
||||||
margin: 8px 0;
|
margin: 8px 0;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
@ -83,11 +83,11 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic, isGro
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [model?.provider, showMinappIcon])
|
}, [model?.provider, showMinappIcon])
|
||||||
|
|
||||||
const hideHeader = isBubbleStyle ? isUserMessage && !isMultiSelectMode : false
|
const userNameJustifyContent = useMemo(() => {
|
||||||
|
if (!isBubbleStyle) return 'flex-start'
|
||||||
if (hideHeader) {
|
if (isUserMessage && !isMultiSelectMode) return 'flex-end'
|
||||||
return null
|
return 'flex-start'
|
||||||
}
|
}, [isBubbleStyle, isUserMessage, isMultiSelectMode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="message-header">
|
<Container className="message-header">
|
||||||
@ -121,7 +121,7 @@ const MessageHeader: FC<Props> = memo(({ assistant, model, message, topic, isGro
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<UserWrap>
|
<UserWrap>
|
||||||
<HStack alignItems="center">
|
<HStack alignItems="center" justifyContent={userNameJustifyContent}>
|
||||||
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
<UserName isBubbleStyle={isBubbleStyle} theme={theme}>
|
||||||
{username}
|
{username}
|
||||||
</UserName>
|
</UserName>
|
||||||
|
|||||||
@ -63,7 +63,10 @@ const Prompt: FC<Props> = ({ assistant, topic }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="system-prompt" onClick={() => AssistantSettingsPopup.show({ assistant })} $isDark={isDark}>
|
<Container
|
||||||
|
className="system-prompt"
|
||||||
|
onClick={() => AssistantSettingsPopup.show({ assistant, tab: 'prompt' })}
|
||||||
|
$isDark={isDark}>
|
||||||
<Text $isVisible={isVisible}>{displayText}</Text>
|
<Text $isVisible={isVisible}>{displayText}</Text>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
import type { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
|
||||||
import { SettingDivider } from '@renderer/pages/settings'
|
|
||||||
import { SessionSettingsPopup } from '@renderer/pages/settings/AgentSettings'
|
|
||||||
import AdvancedSettings from '@renderer/pages/settings/AgentSettings/AdvancedSettings'
|
|
||||||
import EssentialSettings from '@renderer/pages/settings/AgentSettings/EssentialSettings'
|
|
||||||
import type { GetAgentSessionResponse } from '@renderer/types'
|
|
||||||
import { Button } from 'antd'
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
session: GetAgentSessionResponse | undefined | null
|
|
||||||
update: ReturnType<typeof useUpdateSession>['updateSession']
|
|
||||||
}
|
|
||||||
|
|
||||||
const SessionSettingsTab: FC<Props> = ({ session, update }) => {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
|
|
||||||
const onMoreSetting = () => {
|
|
||||||
if (session?.id) {
|
|
||||||
SessionSettingsPopup.show({
|
|
||||||
agentId: session.agent_id,
|
|
||||||
sessionId: session.id
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!session) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-[var(--assistants-width)] p-2 px-3 pt-4">
|
|
||||||
<EssentialSettings agentBase={session} update={update} showModelSetting={false} />
|
|
||||||
<SettingDivider />
|
|
||||||
<AdvancedSettings agentBase={session} update={update} />
|
|
||||||
<SettingDivider />
|
|
||||||
<Button size="small" block onClick={onMoreSetting}>
|
|
||||||
{t('settings.moresetting.label')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SessionSettingsTab
|
|
||||||
@ -1,24 +1,17 @@
|
|||||||
import EditableNumber from '@renderer/components/EditableNumber'
|
import EditableNumber from '@renderer/components/EditableNumber'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import Selector from '@renderer/components/Selector'
|
import Selector from '@renderer/components/Selector'
|
||||||
import { HelpTooltip } from '@renderer/components/TooltipIcons'
|
import { HelpTooltip } from '@renderer/components/TooltipIcons'
|
||||||
import {
|
|
||||||
DEFAULT_CONTEXTCOUNT,
|
|
||||||
DEFAULT_MAX_TOKENS,
|
|
||||||
DEFAULT_TEMPERATURE,
|
|
||||||
MAX_CONTEXT_COUNT
|
|
||||||
} from '@renderer/config/constant'
|
|
||||||
import { isOpenAIModel, isSupportVerbosityModel } from '@renderer/config/models'
|
import { isOpenAIModel, isSupportVerbosityModel } from '@renderer/config/models'
|
||||||
import { UNKNOWN } from '@renderer/config/translate'
|
import { UNKNOWN } from '@renderer/config/translate'
|
||||||
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { useTheme } from '@renderer/context/ThemeProvider'
|
||||||
import { useAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useProvider } from '@renderer/hooks/useProvider'
|
import { useProvider } from '@renderer/hooks/useProvider'
|
||||||
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import useTranslate from '@renderer/hooks/useTranslate'
|
import useTranslate from '@renderer/hooks/useTranslate'
|
||||||
import { SettingDivider, SettingRow, SettingRowTitle } from '@renderer/pages/settings'
|
import { SettingDivider, SettingRow, SettingRowTitle } from '@renderer/pages/settings'
|
||||||
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
|
||||||
import { CollapsibleSettingGroup } from '@renderer/pages/settings/SettingGroup'
|
import { CollapsibleSettingGroup } from '@renderer/pages/settings/SettingGroup'
|
||||||
import { getDefaultModel } from '@renderer/services/AssistantService'
|
import { getDefaultModel } from '@renderer/services/AssistantService'
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
@ -52,19 +45,17 @@ import {
|
|||||||
setShowTranslateConfirm,
|
setShowTranslateConfirm,
|
||||||
setThoughtAutoCollapse
|
setThoughtAutoCollapse
|
||||||
} from '@renderer/store/settings'
|
} from '@renderer/store/settings'
|
||||||
import type { Assistant, AssistantSettings, CodeStyleVarious, MathEngine } from '@renderer/types'
|
import type { Assistant, CodeStyleVarious, MathEngine } from '@renderer/types'
|
||||||
import { isGroqSystemProvider, ThemeMode } from '@renderer/types'
|
import { isGroqSystemProvider, ThemeMode } from '@renderer/types'
|
||||||
import { modalConfirm } from '@renderer/utils'
|
|
||||||
import { getSendMessageShortcutLabel } from '@renderer/utils/input'
|
import { getSendMessageShortcutLabel } from '@renderer/utils/input'
|
||||||
import {
|
import {
|
||||||
isOpenAICompatibleProvider,
|
isOpenAICompatibleProvider,
|
||||||
isSupportServiceTierProvider,
|
isSupportServiceTierProvider,
|
||||||
isSupportVerbosityProvider
|
isSupportVerbosityProvider
|
||||||
} from '@renderer/utils/provider'
|
} from '@renderer/utils/provider'
|
||||||
import { Button, Col, InputNumber, Row, Slider, Switch } from 'antd'
|
import { Col, Row, Slider, Switch } from 'antd'
|
||||||
import { Settings2 } from 'lucide-react'
|
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -76,20 +67,15 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SettingsTab: FC<Props> = (props) => {
|
const SettingsTab: FC<Props> = (props) => {
|
||||||
const { assistant, updateAssistantSettings } = useAssistant(props.assistant.id)
|
const { chat } = useRuntime()
|
||||||
|
const { assistant } = useAssistant(props.assistant.id)
|
||||||
const { provider } = useProvider(assistant.model.provider)
|
const { provider } = useProvider(assistant.model.provider)
|
||||||
|
|
||||||
const { messageStyle, fontSize, language } = useSettings()
|
const { messageStyle, fontSize, language } = useSettings()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const { themeNames } = useCodeStyle()
|
const { themeNames } = useCodeStyle()
|
||||||
|
|
||||||
const [temperature, setTemperature] = useState(assistant?.settings?.temperature ?? DEFAULT_TEMPERATURE)
|
|
||||||
const [enableTemperature, setEnableTemperature] = useState(assistant?.settings?.enableTemperature ?? true)
|
|
||||||
const [contextCount, setContextCount] = useState(assistant?.settings?.contextCount ?? DEFAULT_CONTEXTCOUNT)
|
|
||||||
const [enableMaxTokens, setEnableMaxTokens] = useState(assistant?.settings?.enableMaxTokens ?? false)
|
|
||||||
const [maxTokens, setMaxTokens] = useState(assistant?.settings?.maxTokens ?? 0)
|
|
||||||
const [fontSizeValue, setFontSizeValue] = useState(fontSize)
|
const [fontSizeValue, setFontSizeValue] = useState(fontSize)
|
||||||
const [streamOutput, setStreamOutput] = useState(assistant?.settings?.streamOutput)
|
|
||||||
const { translateLanguages } = useTranslate()
|
const { translateLanguages } = useTranslate()
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -128,28 +114,6 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
confirmRegenerateMessage
|
confirmRegenerateMessage
|
||||||
} = useSettings()
|
} = useSettings()
|
||||||
|
|
||||||
const onUpdateAssistantSettings = (settings: Partial<AssistantSettings>) => {
|
|
||||||
updateAssistantSettings(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onTemperatureChange = (value) => {
|
|
||||||
if (!isNaN(value as number)) {
|
|
||||||
onUpdateAssistantSettings({ temperature: value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onContextCountChange = (value) => {
|
|
||||||
if (!isNaN(value as number)) {
|
|
||||||
onUpdateAssistantSettings({ contextCount: value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onMaxTokensChange = (value) => {
|
|
||||||
if (!isNaN(value as number)) {
|
|
||||||
onUpdateAssistantSettings({ maxTokens: value })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const codeStyle = useMemo(() => {
|
const codeStyle = useMemo(() => {
|
||||||
return codeEditor.enabled
|
return codeEditor.enabled
|
||||||
? theme === ThemeMode.light
|
? theme === ThemeMode.light
|
||||||
@ -176,15 +140,6 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
[dispatch, theme, codeEditor.enabled]
|
[dispatch, theme, codeEditor.enabled]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setTemperature(assistant?.settings?.temperature ?? DEFAULT_TEMPERATURE)
|
|
||||||
setEnableTemperature(assistant?.settings?.enableTemperature ?? true)
|
|
||||||
setContextCount(assistant?.settings?.contextCount ?? DEFAULT_CONTEXTCOUNT)
|
|
||||||
setEnableMaxTokens(assistant?.settings?.enableMaxTokens ?? false)
|
|
||||||
setMaxTokens(assistant?.settings?.maxTokens ?? DEFAULT_MAX_TOKENS)
|
|
||||||
setStreamOutput(assistant?.settings?.streamOutput ?? true)
|
|
||||||
}, [assistant])
|
|
||||||
|
|
||||||
const model = assistant.model || getDefaultModel()
|
const model = assistant.model || getDefaultModel()
|
||||||
|
|
||||||
const showOpenAiSettings =
|
const showOpenAiSettings =
|
||||||
@ -193,173 +148,36 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
isSupportServiceTierProvider(provider) ||
|
isSupportServiceTierProvider(provider) ||
|
||||||
(isSupportVerbosityModel(model) && isSupportVerbosityProvider(provider))
|
(isSupportVerbosityModel(model) && isSupportVerbosityProvider(provider))
|
||||||
|
|
||||||
|
const isTopicSettings = chat.activeTopicOrSession === 'topic'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className="settings-tab">
|
<Container className="settings-tab">
|
||||||
{props.assistant.id !== 'fake' && (
|
{isTopicSettings && (
|
||||||
<CollapsibleSettingGroup
|
<>
|
||||||
title={t('assistants.settings.title')}
|
{showOpenAiSettings && (
|
||||||
defaultExpanded={true}
|
<OpenAISettingsGroup
|
||||||
extra={
|
model={model}
|
||||||
<HStack alignItems="center" gap={2}>
|
providerId={provider.id}
|
||||||
<Button
|
SettingGroup={SettingGroup}
|
||||||
type="text"
|
SettingRowTitleSmall={SettingRowTitleSmall}
|
||||||
size="small"
|
/>
|
||||||
icon={<Settings2 size={16} />}
|
)}
|
||||||
onClick={() => AssistantSettingsPopup.show({ assistant, tab: 'model' })}
|
{isGroqSystemProvider(provider) && (
|
||||||
/>
|
<GroqSettingsGroup SettingGroup={SettingGroup} SettingRowTitleSmall={SettingRowTitleSmall} />
|
||||||
</HStack>
|
)}
|
||||||
}>
|
</>
|
||||||
<SettingGroup style={{ marginTop: 5 }}>
|
|
||||||
<Row align="middle">
|
|
||||||
<SettingRowTitleSmall>
|
|
||||||
{t('chat.settings.temperature.label')}
|
|
||||||
<HelpTooltip title={t('chat.settings.temperature.tip')} />
|
|
||||||
</SettingRowTitleSmall>
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
style={{ marginLeft: 'auto' }}
|
|
||||||
checked={enableTemperature}
|
|
||||||
onChange={(enabled) => {
|
|
||||||
setEnableTemperature(enabled)
|
|
||||||
onUpdateAssistantSettings({ enableTemperature: enabled })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Row>
|
|
||||||
{enableTemperature ? (
|
|
||||||
<Row align="middle" gutter={10}>
|
|
||||||
<Col span={23}>
|
|
||||||
<Slider
|
|
||||||
min={0}
|
|
||||||
max={2}
|
|
||||||
onChange={setTemperature}
|
|
||||||
onChangeComplete={onTemperatureChange}
|
|
||||||
value={typeof temperature === 'number' ? temperature : 0}
|
|
||||||
step={0.1}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
) : (
|
|
||||||
<SettingDivider />
|
|
||||||
)}
|
|
||||||
<Row align="middle" gutter={10} justify="space-between">
|
|
||||||
<SettingRowTitleSmall>
|
|
||||||
{t('chat.settings.context_count.label')}
|
|
||||||
<HelpTooltip title={t('chat.settings.context_count.tip')} />
|
|
||||||
</SettingRowTitleSmall>
|
|
||||||
<Col span={8}>
|
|
||||||
<EditableNumber
|
|
||||||
min={0}
|
|
||||||
max={20}
|
|
||||||
step={1}
|
|
||||||
value={contextCount}
|
|
||||||
changeOnBlur
|
|
||||||
onChange={(value) => {
|
|
||||||
if (value !== null && value >= 0 && value <= 20) {
|
|
||||||
setContextCount(value)
|
|
||||||
onContextCountChange(value)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
formatter={(value) => (value === MAX_CONTEXT_COUNT ? t('chat.settings.max') : (value ?? ''))}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<Row align="middle" gutter={10}>
|
|
||||||
<Col span={24}>
|
|
||||||
<Slider
|
|
||||||
min={0}
|
|
||||||
max={20}
|
|
||||||
onChange={setContextCount}
|
|
||||||
onChangeComplete={onContextCountChange}
|
|
||||||
value={Math.min(contextCount, 20)}
|
|
||||||
tooltip={{ open: false }}
|
|
||||||
step={1}
|
|
||||||
marks={{
|
|
||||||
0: '0',
|
|
||||||
10: '10',
|
|
||||||
20: '20'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
<SettingDivider />
|
|
||||||
<SettingRow>
|
|
||||||
<SettingRowTitleSmall>{t('models.stream_output')}</SettingRowTitleSmall>
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
checked={streamOutput}
|
|
||||||
onChange={(checked) => {
|
|
||||||
setStreamOutput(checked)
|
|
||||||
onUpdateAssistantSettings({ streamOutput: checked })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SettingRow>
|
|
||||||
<SettingDivider />
|
|
||||||
<SettingRow>
|
|
||||||
<Row align="middle">
|
|
||||||
<SettingRowTitleSmall>
|
|
||||||
{t('chat.settings.max_tokens.label')}
|
|
||||||
<HelpTooltip title={t('chat.settings.max_tokens.tip')} />
|
|
||||||
</SettingRowTitleSmall>
|
|
||||||
</Row>
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
checked={enableMaxTokens}
|
|
||||||
onChange={async (enabled) => {
|
|
||||||
if (enabled) {
|
|
||||||
const confirmed = await modalConfirm({
|
|
||||||
title: t('chat.settings.max_tokens.confirm'),
|
|
||||||
content: t('chat.settings.max_tokens.confirm_content'),
|
|
||||||
okButtonProps: {
|
|
||||||
danger: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!confirmed) return
|
|
||||||
}
|
|
||||||
setEnableMaxTokens(enabled)
|
|
||||||
onUpdateAssistantSettings({ enableMaxTokens: enabled })
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SettingRow>
|
|
||||||
{enableMaxTokens && (
|
|
||||||
<Row align="middle" gutter={10} style={{ marginTop: 10 }}>
|
|
||||||
<Col span={24}>
|
|
||||||
<InputNumber
|
|
||||||
disabled={!enableMaxTokens}
|
|
||||||
min={0}
|
|
||||||
max={10000000}
|
|
||||||
step={100}
|
|
||||||
value={typeof maxTokens === 'number' ? maxTokens : 0}
|
|
||||||
changeOnBlur
|
|
||||||
onChange={(value) => value && setMaxTokens(value)}
|
|
||||||
onBlur={() => onMaxTokensChange(maxTokens)}
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
)}
|
|
||||||
<SettingDivider />
|
|
||||||
</SettingGroup>
|
|
||||||
</CollapsibleSettingGroup>
|
|
||||||
)}
|
|
||||||
{showOpenAiSettings && (
|
|
||||||
<OpenAISettingsGroup
|
|
||||||
model={model}
|
|
||||||
providerId={provider.id}
|
|
||||||
SettingGroup={SettingGroup}
|
|
||||||
SettingRowTitleSmall={SettingRowTitleSmall}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isGroqSystemProvider(provider) && (
|
|
||||||
<GroqSettingsGroup SettingGroup={SettingGroup} SettingRowTitleSmall={SettingRowTitleSmall} />
|
|
||||||
)}
|
)}
|
||||||
<CollapsibleSettingGroup title={t('settings.messages.title')} defaultExpanded={true}>
|
<CollapsibleSettingGroup title={t('settings.messages.title')} defaultExpanded={true}>
|
||||||
<SettingGroup>
|
<SettingGroup>
|
||||||
<SettingRow>
|
{isTopicSettings && (
|
||||||
<SettingRowTitleSmall>{t('settings.messages.prompt')}</SettingRowTitleSmall>
|
<>
|
||||||
<Switch size="small" checked={showPrompt} onChange={(checked) => dispatch(setShowPrompt(checked))} />
|
<SettingRow>
|
||||||
</SettingRow>
|
<SettingRowTitleSmall>{t('settings.messages.prompt')}</SettingRowTitleSmall>
|
||||||
<SettingDivider />
|
<Switch size="small" checked={showPrompt} onChange={(checked) => dispatch(setShowPrompt(checked))} />
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitleSmall>{t('settings.messages.use_serif_font')}</SettingRowTitleSmall>
|
<SettingRowTitleSmall>{t('settings.messages.use_serif_font')}</SettingRowTitleSmall>
|
||||||
<Switch
|
<Switch
|
||||||
@ -381,15 +199,19 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
{isTopicSettings && (
|
||||||
<SettingRowTitleSmall>{t('settings.messages.show_message_outline')}</SettingRowTitleSmall>
|
<>
|
||||||
<Switch
|
<SettingRow>
|
||||||
size="small"
|
<SettingRowTitleSmall>{t('settings.messages.show_message_outline')}</SettingRowTitleSmall>
|
||||||
checked={showMessageOutline}
|
<Switch
|
||||||
onChange={(checked) => dispatch(setShowMessageOutline(checked))}
|
size="small"
|
||||||
/>
|
checked={showMessageOutline}
|
||||||
</SettingRow>
|
onChange={(checked) => dispatch(setShowMessageOutline(checked))}
|
||||||
<SettingDivider />
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall>
|
<SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Selector
|
||||||
@ -402,20 +224,24 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
/>
|
/>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
{isTopicSettings && (
|
||||||
<SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall>
|
<>
|
||||||
<Selector
|
<SettingRow>
|
||||||
value={multiModelMessageStyle}
|
<SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall>
|
||||||
onChange={(value) => dispatch(setMultiModelMessageStyle(value))}
|
<Selector
|
||||||
options={[
|
value={multiModelMessageStyle}
|
||||||
{ value: 'fold', label: t('message.message.multi_model_style.fold.label') },
|
onChange={(value) => dispatch(setMultiModelMessageStyle(value))}
|
||||||
{ value: 'vertical', label: t('message.message.multi_model_style.vertical') },
|
options={[
|
||||||
{ value: 'horizontal', label: t('message.message.multi_model_style.horizontal') },
|
{ value: 'fold', label: t('message.message.multi_model_style.fold.label') },
|
||||||
{ value: 'grid', label: t('message.message.multi_model_style.grid') }
|
{ value: 'vertical', label: t('message.message.multi_model_style.vertical') },
|
||||||
]}
|
{ value: 'horizontal', label: t('message.message.multi_model_style.horizontal') },
|
||||||
/>
|
{ value: 'grid', label: t('message.message.multi_model_style.grid') }
|
||||||
</SettingRow>
|
]}
|
||||||
<SettingDivider />
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall>
|
<SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Selector
|
||||||
@ -627,15 +453,19 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</CollapsibleSettingGroup>
|
</CollapsibleSettingGroup>
|
||||||
<CollapsibleSettingGroup title={t('settings.messages.input.title')} defaultExpanded={false}>
|
<CollapsibleSettingGroup title={t('settings.messages.input.title')} defaultExpanded={false}>
|
||||||
<SettingGroup>
|
<SettingGroup>
|
||||||
<SettingRow>
|
{isTopicSettings && (
|
||||||
<SettingRowTitleSmall>{t('settings.messages.input.show_estimated_tokens')}</SettingRowTitleSmall>
|
<>
|
||||||
<Switch
|
<SettingRow>
|
||||||
size="small"
|
<SettingRowTitleSmall>{t('settings.messages.input.show_estimated_tokens')}</SettingRowTitleSmall>
|
||||||
checked={showInputEstimatedTokens}
|
<Switch
|
||||||
onChange={(checked) => dispatch(setShowInputEstimatedTokens(checked))}
|
size="small"
|
||||||
/>
|
checked={showInputEstimatedTokens}
|
||||||
</SettingRow>
|
onChange={(checked) => dispatch(setShowInputEstimatedTokens(checked))}
|
||||||
<SettingDivider />
|
/>
|
||||||
|
</SettingRow>
|
||||||
|
<SettingDivider />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
<SettingRowTitleSmall>{t('settings.messages.input.paste_long_text_as_file')}</SettingRowTitleSmall>
|
<SettingRowTitleSmall>{t('settings.messages.input.paste_long_text_as_file')}</SettingRowTitleSmall>
|
||||||
<Switch
|
<Switch
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { DeleteIcon, EditIcon } from '@renderer/components/Icons'
|
import { DeleteIcon, EditIcon } from '@renderer/components/Icons'
|
||||||
import { useSessions } from '@renderer/hooks/agents/useSessions'
|
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import AgentSettingsPopup from '@renderer/pages/settings/AgentSettings/AgentSettingsPopup'
|
import AgentSettingsPopup from '@renderer/pages/settings/AgentSettings/AgentSettingsPopup'
|
||||||
import { AgentLabel } from '@renderer/pages/settings/AgentSettings/shared'
|
import { AgentLabel } from '@renderer/pages/settings/AgentSettings/shared'
|
||||||
@ -8,7 +7,7 @@ import type { AgentEntity } from '@renderer/types'
|
|||||||
import { cn } from '@renderer/utils'
|
import { cn } from '@renderer/utils'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import { Dropdown, Tooltip } from 'antd'
|
import { Dropdown, Tooltip } from 'antd'
|
||||||
import { Bot } from 'lucide-react'
|
import { Bot, MoreVertical } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { memo, useCallback, useMemo } from 'react'
|
import { memo, useCallback, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@ -24,8 +23,7 @@ interface AgentItemProps {
|
|||||||
|
|
||||||
const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) => {
|
const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { sessions } = useSessions(agent.id)
|
const { clickAssistantToShowTopic, topicPosition, assistantIconType } = useSettings()
|
||||||
const { clickAssistantToShowTopic, topicPosition } = useSettings()
|
|
||||||
|
|
||||||
const handlePress = useCallback(() => {
|
const handlePress = useCallback(() => {
|
||||||
// Show session sidebar if setting is enabled (reusing the assistant setting for consistency)
|
// Show session sidebar if setting is enabled (reusing the assistant setting for consistency)
|
||||||
@ -37,6 +35,14 @@ const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) =
|
|||||||
onPress()
|
onPress()
|
||||||
}, [clickAssistantToShowTopic, topicPosition, onPress])
|
}, [clickAssistantToShowTopic, topicPosition, onPress])
|
||||||
|
|
||||||
|
const handleMoreClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
agent.id && AgentSettingsPopup.show({ agentId: agent.id })
|
||||||
|
},
|
||||||
|
[agent.id]
|
||||||
|
)
|
||||||
|
|
||||||
const menuItems: MenuProps['items'] = useMemo(
|
const menuItems: MenuProps['items'] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@ -72,14 +78,14 @@ const AgentItem: FC<AgentItemProps> = ({ agent, isActive, onDelete, onPress }) =
|
|||||||
<Container onClick={handlePress} isActive={isActive}>
|
<Container onClick={handlePress} isActive={isActive}>
|
||||||
<AssistantNameRow className="name" title={agent.name ?? agent.id}>
|
<AssistantNameRow className="name" title={agent.name ?? agent.id}>
|
||||||
<AgentNameWrapper>
|
<AgentNameWrapper>
|
||||||
<AgentLabel agent={agent} />
|
<AgentLabel agent={agent} hideIcon={assistantIconType === 'none'} />
|
||||||
</AgentNameWrapper>
|
</AgentNameWrapper>
|
||||||
{isActive && (
|
{isActive && (
|
||||||
<MenuButton>
|
<MenuButton onClick={handleMoreClick}>
|
||||||
<SessionCount>{sessions.length}</SessionCount>
|
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
)}
|
)}
|
||||||
{!isActive && <BotIcon />}
|
{!isActive && assistantIconType !== 'none' && <BotIcon />}
|
||||||
</AssistantNameRow>
|
</AssistantNameRow>
|
||||||
</Container>
|
</Container>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
@ -116,7 +122,7 @@ export const AgentNameWrapper: React.FC<React.HTMLAttributes<HTMLDivElement>> =
|
|||||||
export const MenuButton: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
|
export const MenuButton: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({ className, ...props }) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-5 min-h-5 w-5 flex-row items-center justify-center rounded-full border border-[var(--color-border)] bg-[var(--color-background)]',
|
'flex h-[22px] min-h-[22px] min-w-[22px] flex-row items-center justify-center rounded-[11px] border-[0.5px] border-[var(--color-border)] bg-[var(--color-background)] px-[5px]',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
ArrowUpAZ,
|
ArrowUpAZ,
|
||||||
BrushCleaning,
|
BrushCleaning,
|
||||||
Check,
|
Check,
|
||||||
|
MoreVertical,
|
||||||
Plus,
|
Plus,
|
||||||
Save,
|
Save,
|
||||||
Settings2,
|
Settings2,
|
||||||
@ -150,6 +151,14 @@ const AssistantItem: FC<AssistantItemProps> = ({
|
|||||||
[assistant.emoji, assistantName]
|
[assistant.emoji, assistantName]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const handleMoreClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
AssistantSettingsPopup.show({ assistant })
|
||||||
|
},
|
||||||
|
[assistant]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{ items: menuItems }}
|
menu={{ items: menuItems }}
|
||||||
@ -174,8 +183,8 @@ const AssistantItem: FC<AssistantItemProps> = ({
|
|||||||
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
|
<AssistantName className="text-nowrap">{assistantName}</AssistantName>
|
||||||
</AssistantNameRow>
|
</AssistantNameRow>
|
||||||
{isActive && (
|
{isActive && (
|
||||||
<MenuButton onClick={() => EventEmitter.emit(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR)}>
|
<MenuButton onClick={handleMoreClick}>
|
||||||
<TopicCount className="topics-count">{assistant.topics.length}</TopicCount>
|
<MoreVertical size={14} className="text-[var(--color-text-secondary)]" />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
@ -447,19 +456,4 @@ const MenuButton = ({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const TopicCount = ({
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: PropsWithChildren<{} & React.HTMLAttributes<HTMLDivElement>>) => (
|
|
||||||
<div
|
|
||||||
{...props}
|
|
||||||
className={cn(
|
|
||||||
'flex flex-row items-center justify-center rounded-[10px] text-[10px] text-[var(--color-text)]',
|
|
||||||
className
|
|
||||||
)}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
export default memo(AssistantItem)
|
export default memo(AssistantItem)
|
||||||
|
|||||||
@ -232,12 +232,11 @@ const SessionListItem = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.singlealone {
|
&.singlealone {
|
||||||
border-radius: 0 !important;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-background-soft);
|
background-color: var(--color-background-soft);
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
border-left: 2px solid var(--color-primary);
|
background-color: var(--color-background-mute);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,8 +19,6 @@ import styled from 'styled-components'
|
|||||||
import AddButton from './AddButton'
|
import AddButton from './AddButton'
|
||||||
import SessionItem from './SessionItem'
|
import SessionItem from './SessionItem'
|
||||||
|
|
||||||
// const logger = loggerService.withContext('SessionsTab')
|
|
||||||
|
|
||||||
interface SessionsProps {
|
interface SessionsProps {
|
||||||
agentId: string
|
agentId: string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -499,7 +499,7 @@ export const Topics: React.FC<Props> = ({ assistant: _assistant, activeTopic, se
|
|||||||
className="topics-tab"
|
className="topics-tab"
|
||||||
list={sortedTopics}
|
list={sortedTopics}
|
||||||
onUpdate={updateTopics}
|
onUpdate={updateTopics}
|
||||||
style={{ height: '100%', padding: '11px 0 10px 10px' }}
|
style={{ height: '100%', padding: '9px 0 10px 10px' }}
|
||||||
itemContainerStyle={{ paddingBottom: '8px' }}
|
itemContainerStyle={{ paddingBottom: '8px' }}
|
||||||
header={
|
header={
|
||||||
<>
|
<>
|
||||||
@ -632,12 +632,11 @@ const TopicListItem = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.singlealone {
|
&.singlealone {
|
||||||
border-radius: 0 !important;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-background-soft);
|
background-color: var(--color-background-soft);
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
border-left: 2px solid var(--color-primary);
|
background-color: var(--color-background-mute);
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
|
import AddAssistantPopup from '@renderer/components/Popups/AddAssistantPopup'
|
||||||
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
|
|
||||||
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
|
||||||
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
|
||||||
import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings'
|
import { useNavbarPosition, useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useShowTopics } from '@renderer/hooks/useStore'
|
import { useShowTopics } from '@renderer/hooks/useStore'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
@ -10,16 +7,13 @@ import { useAppDispatch } from '@renderer/store'
|
|||||||
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
||||||
import type { Assistant, Topic } from '@renderer/types'
|
import type { Assistant, Topic } from '@renderer/types'
|
||||||
import type { Tab } from '@renderer/types/chat'
|
import type { Tab } from '@renderer/types/chat'
|
||||||
import { classNames, getErrorMessage, uuid } from '@renderer/utils'
|
import { classNames, uuid } from '@renderer/utils'
|
||||||
import { Alert, Skeleton } from 'antd'
|
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import Assistants from './AssistantsTab'
|
import Assistants from './AssistantsTab'
|
||||||
import SessionSettingsTab from './SessionSettingsTab'
|
|
||||||
import Settings from './SettingsTab'
|
|
||||||
import Topics from './TopicsTab'
|
import Topics from './TopicsTab'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -49,15 +43,8 @@ const HomeTabs: FC<Props> = ({
|
|||||||
const { toggleShowTopics } = useShowTopics()
|
const { toggleShowTopics } = useShowTopics()
|
||||||
const { isLeftNavbar } = useNavbarPosition()
|
const { isLeftNavbar } = useNavbarPosition()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { chat } = useRuntime()
|
|
||||||
const { activeTopicOrSession, activeAgentId } = chat
|
|
||||||
const { session, isLoading: isSessionLoading, error: sessionError } = useActiveSession()
|
|
||||||
const { updateSession } = useUpdateSession(activeAgentId)
|
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
const isSessionView = activeTopicOrSession === 'session'
|
|
||||||
const isTopicView = activeTopicOrSession === 'topic'
|
|
||||||
|
|
||||||
const [tab, setTab] = useState<Tab>(position === 'left' ? _tab || 'assistants' : 'topic')
|
const [tab, setTab] = useState<Tab>(position === 'left' ? _tab || 'assistants' : 'topic')
|
||||||
const borderStyle = '0.5px solid var(--color-border)'
|
const borderStyle = '0.5px solid var(--color-border)'
|
||||||
const border =
|
const border =
|
||||||
@ -96,9 +83,6 @@ const HomeTabs: FC<Props> = ({
|
|||||||
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
EventEmitter.on(EVENT_NAMES.SHOW_TOPIC_SIDEBAR, (): any => {
|
||||||
showTab && setTab('topic')
|
showTab && setTab('topic')
|
||||||
}),
|
}),
|
||||||
EventEmitter.on(EVENT_NAMES.SHOW_CHAT_SETTINGS, (): any => {
|
|
||||||
showTab && setTab('settings')
|
|
||||||
}),
|
|
||||||
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => {
|
EventEmitter.on(EVENT_NAMES.SWITCH_TOPIC_SIDEBAR, () => {
|
||||||
showTab && setTab('topic')
|
showTab && setTab('topic')
|
||||||
if (position === 'left' && topicPosition === 'right') {
|
if (position === 'left' && topicPosition === 'right') {
|
||||||
@ -113,7 +97,7 @@ const HomeTabs: FC<Props> = ({
|
|||||||
if (position === 'right' && topicPosition === 'right' && tab === 'assistants') {
|
if (position === 'right' && topicPosition === 'right' && tab === 'assistants') {
|
||||||
setTab('topic')
|
setTab('topic')
|
||||||
}
|
}
|
||||||
if (position === 'left' && topicPosition === 'right' && (tab === 'topic' || tab === 'settings')) {
|
if (position === 'left' && topicPosition === 'right' && tab === 'topic') {
|
||||||
setTab('assistants')
|
setTab('assistants')
|
||||||
}
|
}
|
||||||
}, [position, tab, topicPosition, forceToSeeAllTab])
|
}, [position, tab, topicPosition, forceToSeeAllTab])
|
||||||
@ -130,20 +114,6 @@ const HomeTabs: FC<Props> = ({
|
|||||||
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
|
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
|
||||||
{t('common.topics')}
|
{t('common.topics')}
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem active={tab === 'settings'} onClick={() => setTab('settings')}>
|
|
||||||
{t('settings.title')}
|
|
||||||
</TabItem>
|
|
||||||
</CustomTabs>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{position === 'right' && topicPosition === 'right' && (
|
|
||||||
<CustomTabs>
|
|
||||||
<TabItem active={tab === 'topic'} onClick={() => setTab('topic')}>
|
|
||||||
{t('common.topics')}
|
|
||||||
</TabItem>
|
|
||||||
<TabItem active={tab === 'settings'} onClick={() => setTab('settings')}>
|
|
||||||
{t('settings.title')}
|
|
||||||
</TabItem>
|
|
||||||
</CustomTabs>
|
</CustomTabs>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -164,22 +134,6 @@ const HomeTabs: FC<Props> = ({
|
|||||||
position={position}
|
position={position}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{tab === 'settings' && isTopicView && <Settings assistant={activeAssistant} />}
|
|
||||||
{tab === 'settings' && isSessionView && !sessionError && (
|
|
||||||
<Skeleton loading={isSessionLoading} active style={{ height: '100%', padding: '16px' }}>
|
|
||||||
<SessionSettingsTab session={session} update={updateSession} />
|
|
||||||
</Skeleton>
|
|
||||||
)}
|
|
||||||
{tab === 'settings' && isSessionView && sessionError && (
|
|
||||||
<div className="w-[var(--assistants-width)] p-2 px-3 pt-4">
|
|
||||||
<Alert
|
|
||||||
type="error"
|
|
||||||
message={t('agent.session.get.error.failed')}
|
|
||||||
description={getErrorMessage(sessionError)}
|
|
||||||
style={{ padding: '10px 15px' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</TabContent>
|
</TabContent>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
|
import EmojiIcon from '@renderer/components/EmojiIcon'
|
||||||
import HorizontalScrollContainer from '@renderer/components/HorizontalScrollContainer'
|
import HorizontalScrollContainer from '@renderer/components/HorizontalScrollContainer'
|
||||||
import { useActiveAgent } from '@renderer/hooks/agents/useActiveAgent'
|
import { useActiveAgent } from '@renderer/hooks/agents/useActiveAgent'
|
||||||
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
|
import { useActiveSession } from '@renderer/hooks/agents/useActiveSession'
|
||||||
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
import { useUpdateSession } from '@renderer/hooks/agents/useUpdateSession'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
|
import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings'
|
||||||
import type { AgentEntity, AgentSessionEntity, ApiModel, Assistant } from '@renderer/types'
|
import type { AgentEntity, AgentSessionEntity, ApiModel, Assistant } from '@renderer/types'
|
||||||
|
import { getLeadingEmoji } from '@renderer/utils'
|
||||||
import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
|
import { formatErrorMessageWithPrefix } from '@renderer/utils/error'
|
||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import { ChevronRight, Folder } from 'lucide-react'
|
import { ChevronRight, Folder } from 'lucide-react'
|
||||||
import type { FC, ReactNode } from 'react'
|
import type { FC, ReactNode } from 'react'
|
||||||
import { useCallback } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { twMerge } from 'tailwind-merge'
|
import { twMerge } from 'tailwind-merge'
|
||||||
|
|
||||||
import { AgentSettingsPopup, SessionSettingsPopup } from '../../settings/AgentSettings'
|
import { AgentSettingsPopup, SessionSettingsPopup } from '../../settings/AgentSettings'
|
||||||
@ -29,6 +32,8 @@ const ChatNavbarContent: FC<Props> = ({ assistant }) => {
|
|||||||
const { session: activeSession } = useActiveSession()
|
const { session: activeSession } = useActiveSession()
|
||||||
const { updateModel } = useUpdateSession(activeAgent?.id ?? null)
|
const { updateModel } = useUpdateSession(activeAgent?.id ?? null)
|
||||||
|
|
||||||
|
const assistantName = useMemo(() => assistant.name || t('chat.default.name'), [assistant.name])
|
||||||
|
|
||||||
const handleUpdateModel = useCallback(
|
const handleUpdateModel = useCallback(
|
||||||
async (model: ApiModel) => {
|
async (model: ApiModel) => {
|
||||||
if (!activeAgent || !activeSession) return
|
if (!activeAgent || !activeSession) return
|
||||||
@ -39,7 +44,25 @@ const ChatNavbarContent: FC<Props> = ({ assistant }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{activeTopicOrSession === 'topic' && <SelectModelButton assistant={assistant} />}
|
{activeTopicOrSession === 'topic' && (
|
||||||
|
<HorizontalScrollContainer className="ml-2 flex-initial">
|
||||||
|
<div className="flex flex-nowrap items-center gap-2">
|
||||||
|
{/* Assistant Label */}
|
||||||
|
<div
|
||||||
|
className="flex h-full cursor-pointer items-center gap-1.5"
|
||||||
|
onClick={() => AssistantSettingsPopup.show({ assistant })}>
|
||||||
|
<EmojiIcon emoji={assistant.emoji || getLeadingEmoji(assistantName)} size={24} />
|
||||||
|
<span className="max-w-40 truncate text-xs">{assistantName}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Separator */}
|
||||||
|
<ChevronRight className="h-4 w-4 text-gray-400" />
|
||||||
|
|
||||||
|
{/* Model Button */}
|
||||||
|
<SelectModelButton assistant={assistant} />
|
||||||
|
</div>
|
||||||
|
</HorizontalScrollContainer>
|
||||||
|
)}
|
||||||
{activeTopicOrSession === 'session' && activeAgent && (
|
{activeTopicOrSession === 'session' && activeAgent && (
|
||||||
<HorizontalScrollContainer className="ml-2 flex-initial">
|
<HorizontalScrollContainer className="ml-2 flex-initial">
|
||||||
<div className="flex flex-nowrap items-center gap-2">
|
<div className="flex flex-nowrap items-center gap-2">
|
||||||
|
|||||||
38
src/renderer/src/pages/home/components/SettingsButton.tsx
Normal file
38
src/renderer/src/pages/home/components/SettingsButton.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import type { Assistant } from '@renderer/types'
|
||||||
|
import { Drawer, Tooltip } from 'antd'
|
||||||
|
import { t } from 'i18next'
|
||||||
|
import { Settings2 } from 'lucide-react'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { NavbarIcon } from '../ChatNavbar'
|
||||||
|
import HomeSettings from '../Tabs/SettingsTab'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
assistant: Assistant
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsButton: FC<Props> = ({ assistant }) => {
|
||||||
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tooltip title={t('settings.title')} mouseEnterDelay={0.8}>
|
||||||
|
<NavbarIcon onClick={() => setSettingsOpen(true)}>
|
||||||
|
<Settings2 size={18} />
|
||||||
|
</NavbarIcon>
|
||||||
|
</Tooltip>
|
||||||
|
<Drawer
|
||||||
|
placement="right"
|
||||||
|
open={settingsOpen}
|
||||||
|
onClose={() => setSettingsOpen(false)}
|
||||||
|
width="var(--assistants-width)"
|
||||||
|
closable={false}
|
||||||
|
styles={{ body: { padding: 0, paddingTop: 'var(--navbar-height)' } }}>
|
||||||
|
<HomeSettings assistant={assistant} />
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SettingsButton
|
||||||
@ -119,7 +119,7 @@ const AgentSettingPopupContainer: React.FC<AgentSettingPopupParams> = ({ tab, ag
|
|||||||
onOk={onOk}
|
onOk={onOk}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
afterClose={afterClose}
|
afterClose={afterClose}
|
||||||
maskClosable={false}
|
maskClosable={menu !== 'prompt'}
|
||||||
footer={null}
|
footer={null}
|
||||||
title={<AgentLabel agent={agent} />}
|
title={<AgentLabel agent={agent} />}
|
||||||
transitionName="animation-move-down"
|
transitionName="animation-move-down"
|
||||||
|
|||||||
@ -29,14 +29,15 @@ export type AgentLabelProps = {
|
|||||||
avatar?: string
|
avatar?: string
|
||||||
name?: string
|
name?: string
|
||||||
}
|
}
|
||||||
|
hideIcon?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AgentLabel: React.FC<AgentLabelProps> = ({ agent, classNames }) => {
|
export const AgentLabel: React.FC<AgentLabelProps> = ({ agent, classNames, hideIcon }) => {
|
||||||
const emoji = agent?.configuration?.avatar
|
const emoji = agent?.configuration?.avatar
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex w-full items-center gap-2 truncate', classNames?.container)}>
|
<div className={cn('flex w-full items-center gap-2 truncate', classNames?.container)}>
|
||||||
<EmojiIcon emoji={emoji || '⭐️'} className={classNames?.avatar} />
|
{!hideIcon && <EmojiIcon emoji={emoji || '⭐️'} className={classNames?.avatar} size={24} />}
|
||||||
<span className={cn('truncate', 'text-[var(--color-text)]', classNames?.name)}>
|
<span className={cn('truncate', 'text-[var(--color-text)]', classNames?.name)}>
|
||||||
{agent?.name ?? (agent?.type ? getAgentTypeLabel(agent.type) : '')}
|
{agent?.name ?? (agent?.type ? getAgentTypeLabel(agent.type) : '')}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -37,7 +37,7 @@ interface Props extends AssistantSettingPopupShowParams {
|
|||||||
const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...props }) => {
|
const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...props }) => {
|
||||||
const [open, setOpen] = useState(true)
|
const [open, setOpen] = useState(true)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [menu, setMenu] = useState<AssistantSettingPopupTab>(tab || 'prompt')
|
const [menu, setMenu] = useState<AssistantSettingPopupTab>(tab || 'model')
|
||||||
|
|
||||||
const _useAssistant = useAssistant(props.assistant.id)
|
const _useAssistant = useAssistant(props.assistant.id)
|
||||||
const _useAgent = useAssistantPreset(props.assistant.id)
|
const _useAgent = useAssistantPreset(props.assistant.id)
|
||||||
@ -64,14 +64,14 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...prop
|
|||||||
}
|
}
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
|
||||||
key: 'prompt',
|
|
||||||
label: t('assistants.settings.prompt')
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'model',
|
key: 'model',
|
||||||
label: t('assistants.settings.model')
|
label: t('assistants.settings.model')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'prompt',
|
||||||
|
label: t('assistants.settings.prompt')
|
||||||
|
},
|
||||||
showKnowledgeIcon && {
|
showKnowledgeIcon && {
|
||||||
key: 'knowledge_base',
|
key: 'knowledge_base',
|
||||||
label: t('assistants.settings.knowledge_base.label')
|
label: t('assistants.settings.knowledge_base.label')
|
||||||
@ -96,7 +96,7 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...prop
|
|||||||
onOk={onOk}
|
onOk={onOk}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
afterClose={afterClose}
|
afterClose={afterClose}
|
||||||
maskClosable={false}
|
maskClosable={menu !== 'prompt'}
|
||||||
footer={null}
|
footer={null}
|
||||||
title={assistant.name}
|
title={assistant.name}
|
||||||
transitionName="animation-move-down"
|
transitionName="animation-move-down"
|
||||||
@ -116,22 +116,22 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ resolve, tab, ...prop
|
|||||||
<HStack>
|
<HStack>
|
||||||
<LeftMenu>
|
<LeftMenu>
|
||||||
<StyledMenu
|
<StyledMenu
|
||||||
defaultSelectedKeys={[tab || 'prompt']}
|
defaultSelectedKeys={[tab || 'model']}
|
||||||
mode="vertical"
|
mode="vertical"
|
||||||
items={items}
|
items={items}
|
||||||
onSelect={({ key }) => setMenu(key as AssistantSettingPopupTab)}
|
onSelect={({ key }) => setMenu(key as AssistantSettingPopupTab)}
|
||||||
/>
|
/>
|
||||||
</LeftMenu>
|
</LeftMenu>
|
||||||
<Settings>
|
<Settings>
|
||||||
{menu === 'prompt' && (
|
{menu === 'model' && (
|
||||||
<AssistantPromptSettings
|
<AssistantModelSettings
|
||||||
assistant={assistant}
|
assistant={assistant}
|
||||||
updateAssistant={updateAssistant}
|
updateAssistant={updateAssistant}
|
||||||
updateAssistantSettings={updateAssistantSettings}
|
updateAssistantSettings={updateAssistantSettings}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{menu === 'model' && (
|
{menu === 'prompt' && (
|
||||||
<AssistantModelSettings
|
<AssistantPromptSettings
|
||||||
assistant={assistant}
|
assistant={assistant}
|
||||||
updateAssistant={updateAssistant}
|
updateAssistant={updateAssistant}
|
||||||
updateAssistantSettings={updateAssistantSettings}
|
updateAssistantSettings={updateAssistantSettings}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ export const EventEmitter = new Emittery()
|
|||||||
|
|
||||||
export const EVENT_NAMES = {
|
export const EVENT_NAMES = {
|
||||||
SEND_MESSAGE: 'SEND_MESSAGE',
|
SEND_MESSAGE: 'SEND_MESSAGE',
|
||||||
// APPEND_MESSAGE: 'APPEND_MESSAGE',
|
|
||||||
// RECEIVE_MESSAGE: 'RECEIVE_MESSAGE',
|
|
||||||
MESSAGE_COMPLETE: 'MESSAGE_COMPLETE',
|
MESSAGE_COMPLETE: 'MESSAGE_COMPLETE',
|
||||||
AI_AUTO_RENAME: 'AI_AUTO_RENAME',
|
AI_AUTO_RENAME: 'AI_AUTO_RENAME',
|
||||||
CLEAR_MESSAGES: 'CLEAR_MESSAGES',
|
CLEAR_MESSAGES: 'CLEAR_MESSAGES',
|
||||||
@ -15,7 +13,6 @@ export const EVENT_NAMES = {
|
|||||||
CHAT_COMPLETION_PAUSED: 'CHAT_COMPLETION_PAUSED',
|
CHAT_COMPLETION_PAUSED: 'CHAT_COMPLETION_PAUSED',
|
||||||
ESTIMATED_TOKEN_COUNT: 'ESTIMATED_TOKEN_COUNT',
|
ESTIMATED_TOKEN_COUNT: 'ESTIMATED_TOKEN_COUNT',
|
||||||
SHOW_ASSISTANTS: 'SHOW_ASSISTANTS',
|
SHOW_ASSISTANTS: 'SHOW_ASSISTANTS',
|
||||||
SHOW_CHAT_SETTINGS: 'SHOW_CHAT_SETTINGS',
|
|
||||||
SHOW_TOPIC_SIDEBAR: 'SHOW_TOPIC_SIDEBAR',
|
SHOW_TOPIC_SIDEBAR: 'SHOW_TOPIC_SIDEBAR',
|
||||||
SWITCH_TOPIC_SIDEBAR: 'SWITCH_TOPIC_SIDEBAR',
|
SWITCH_TOPIC_SIDEBAR: 'SWITCH_TOPIC_SIDEBAR',
|
||||||
NEW_CONTEXT: 'NEW_CONTEXT',
|
NEW_CONTEXT: 'NEW_CONTEXT',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export type Tab = 'assistants' | 'topic' | 'settings'
|
export type Tab = 'assistants' | 'topic'
|
||||||
|
|
||||||
export type InputBarToolType =
|
export type InputBarToolType =
|
||||||
| 'new_topic'
|
| 'new_topic'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user