mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-06 13:19:33 +08:00
feat: add FloatingSidebar component and integrate assistant switching… (#5852)
* feat: add FloatingSidebar component and integrate assistant switching functionality * refactor: simplify FloatingSidebar by removing unused hooks and components * refactor: remove unused AddAssistantPopup and related code from FloatingSidebar * feat: implement sidebar hide cooldown and adjust tooltip delays in Navbar. * feat: integrate HomeTabs into FloatingSidebar and update Navbar props * refactor: remove commented-out code and unused components from FloatingSidebar * fix: update Popover placement from rightTop to bottomRight in FloatingSidebar. * feat: add forceToSeeAllTab prop to HomeTabs for improved tab visibility control * fix: update HomeTabs logic to respect forceToSeeAllTab prop for tab selection * feat: pass position prop to FloatingSidebar and HomeTabs for consistent layout control * feat: integrate FloatingSidebar into Navbar for improved topic visibility and update HomeTabs logic for consistent tab rendering * fix: remove unused showTopics from Navbar component * feat: enhance topic visibility control in Navbar with cooldown logic for sidebar toggle * fix: add onMouseOut handler to NavbarIcon for sidebar cooldown reset --------- Co-authored-by: George Zhao <georgezhao@SKJLAB>
This commit is contained in:
parent
517eaacba9
commit
eec83da19c
90
src/renderer/src/components/Popups/FloatingSidebar.tsx
Normal file
90
src/renderer/src/components/Popups/FloatingSidebar.tsx
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import HomeTabs from '@renderer/pages/home/Tabs/index'
|
||||||
|
import { Assistant, Topic } from '@renderer/types'
|
||||||
|
import { Popover } from 'antd'
|
||||||
|
import { FC, useEffect, useState } from 'react'
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
import Scrollbar from '../Scrollbar'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: React.ReactNode
|
||||||
|
activeAssistant: Assistant
|
||||||
|
setActiveAssistant: (assistant: Assistant) => void
|
||||||
|
activeTopic: Topic
|
||||||
|
setActiveTopic: (topic: Topic) => void
|
||||||
|
position: 'left' | 'right'
|
||||||
|
}
|
||||||
|
|
||||||
|
const FloatingSidebar: FC<Props> = ({
|
||||||
|
children,
|
||||||
|
activeAssistant,
|
||||||
|
setActiveAssistant,
|
||||||
|
activeTopic,
|
||||||
|
setActiveTopic,
|
||||||
|
position = 'left'
|
||||||
|
}) => {
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
|
useHotkeys('esc', () => {
|
||||||
|
setOpen(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
const [maxHeight, setMaxHeight] = useState(Math.floor(window.innerHeight * 0.75))
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
setMaxHeight(Math.floor(window.innerHeight * 0.75))
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<PopoverContent maxHeight={maxHeight}>
|
||||||
|
<HomeTabs
|
||||||
|
activeAssistant={activeAssistant}
|
||||||
|
activeTopic={activeTopic}
|
||||||
|
setActiveAssistant={setActiveAssistant}
|
||||||
|
setActiveTopic={setActiveTopic}
|
||||||
|
position={position}
|
||||||
|
forceToSeeAllTab={true}></HomeTabs>
|
||||||
|
</PopoverContent>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(visible) => {
|
||||||
|
setOpen(visible)
|
||||||
|
}}
|
||||||
|
content={content}
|
||||||
|
trigger={['hover', 'click']}
|
||||||
|
placement="bottomRight"
|
||||||
|
arrow={false}
|
||||||
|
mouseEnterDelay={0.8} // 800ms delay before showing
|
||||||
|
mouseLeaveDelay={20}
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
padding: 0,
|
||||||
|
background: 'var(--color-background)',
|
||||||
|
border: '1px solid var(--color-border)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12)'
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
{children}
|
||||||
|
</Popover>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const PopoverContent = styled(Scrollbar)<{ maxHeight: number }>`
|
||||||
|
max-height: ${(props) => props.maxHeight}px;
|
||||||
|
overflow-y: auto;
|
||||||
|
`
|
||||||
|
|
||||||
|
export default FloatingSidebar
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import { useAssistants } from '@renderer/hooks/useAssistant'
|
import { useAssistants } from '@renderer/hooks/useAssistant'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
import { useActiveTopic } from '@renderer/hooks/useTopic'
|
||||||
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
import NavigationService from '@renderer/services/NavigationService'
|
import NavigationService from '@renderer/services/NavigationService'
|
||||||
import { Assistant } from '@renderer/types'
|
import { Assistant } from '@renderer/types'
|
||||||
import { FC, useEffect, useState } from 'react'
|
import { FC, useEffect, useState } from 'react'
|
||||||
@ -36,6 +37,19 @@ const HomePage: FC = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state])
|
}, [state])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubscribe = EventEmitter.on(EVENT_NAMES.SWITCH_ASSISTANT, (assistantId: string) => {
|
||||||
|
const newAssistant = assistants.find((a) => a.id === assistantId)
|
||||||
|
if (newAssistant) {
|
||||||
|
setActiveAssistant(newAssistant)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
}, [assistants, setActiveAssistant])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canMinimize = topicPosition == 'left' ? !showAssistants : !showAssistants && !showTopics
|
const canMinimize = topicPosition == 'left' ? !showAssistants : !showAssistants && !showTopics
|
||||||
window.api.window.setMinimumSize(canMinimize ? 520 : 1080, 600)
|
window.api.window.setMinimumSize(canMinimize ? 520 : 1080, 600)
|
||||||
@ -47,7 +61,13 @@ const HomePage: FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container id="home-page">
|
<Container id="home-page">
|
||||||
<Navbar activeAssistant={activeAssistant} activeTopic={activeTopic} setActiveTopic={setActiveTopic} />
|
<Navbar
|
||||||
|
activeAssistant={activeAssistant}
|
||||||
|
activeTopic={activeTopic}
|
||||||
|
setActiveTopic={setActiveTopic}
|
||||||
|
setActiveAssistant={setActiveAssistant}
|
||||||
|
position="left"
|
||||||
|
/>
|
||||||
<ContentContainer id="content-container">
|
<ContentContainer id="content-container">
|
||||||
{showAssistants && (
|
{showAssistants && (
|
||||||
<HomeTabs
|
<HomeTabs
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarLeft, NavbarRight } from '@renderer/components/app/Navbar'
|
||||||
import { HStack } from '@renderer/components/Layout'
|
import { HStack } from '@renderer/components/Layout'
|
||||||
|
import FloatingSidebar from '@renderer/components/Popups/FloatingSidebar'
|
||||||
import MinAppsPopover from '@renderer/components/Popups/MinAppsPopover'
|
import MinAppsPopover from '@renderer/components/Popups/MinAppsPopover'
|
||||||
import SearchPopup from '@renderer/components/Popups/SearchPopup'
|
import SearchPopup from '@renderer/components/Popups/SearchPopup'
|
||||||
import { isMac } from '@renderer/config/constant'
|
import { isMac } from '@renderer/config/constant'
|
||||||
@ -15,7 +16,7 @@ import { Assistant, Topic } from '@renderer/types'
|
|||||||
import { Tooltip } from 'antd'
|
import { Tooltip } from 'antd'
|
||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import { LayoutGrid, MessageSquareDiff, PanelLeftClose, PanelRightClose, Search } from 'lucide-react'
|
import { LayoutGrid, MessageSquareDiff, PanelLeftClose, PanelRightClose, Search } from 'lucide-react'
|
||||||
import { FC } from 'react'
|
import { FC, useCallback, useState } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SelectModelButton from './components/SelectModelButton'
|
import SelectModelButton from './components/SelectModelButton'
|
||||||
@ -25,18 +26,47 @@ interface Props {
|
|||||||
activeAssistant: Assistant
|
activeAssistant: Assistant
|
||||||
activeTopic: Topic
|
activeTopic: Topic
|
||||||
setActiveTopic: (topic: Topic) => void
|
setActiveTopic: (topic: Topic) => void
|
||||||
|
setActiveAssistant: (assistant: Assistant) => void
|
||||||
|
position: 'left' | 'right'
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
const HeaderNavbar: FC<Props> = ({ activeAssistant, setActiveAssistant, activeTopic, setActiveTopic }) => {
|
||||||
const { assistant } = useAssistant(activeAssistant.id)
|
const { assistant } = useAssistant(activeAssistant.id)
|
||||||
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
const { showAssistants, toggleShowAssistants } = useShowAssistants()
|
||||||
const { topicPosition, sidebarIcons, narrowMode } = useSettings()
|
const { topicPosition, sidebarIcons, narrowMode } = useSettings()
|
||||||
const { showTopics, toggleShowTopics } = useShowTopics()
|
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
const [sidebarHideCooldown, setSidebarHideCooldown] = useState(false)
|
||||||
|
|
||||||
useShortcut('toggle_show_assistants', () => {
|
// Function to toggle assistants with cooldown
|
||||||
toggleShowAssistants()
|
const handleToggleShowAssistants = useCallback(() => {
|
||||||
})
|
if (showAssistants) {
|
||||||
|
// When hiding sidebar, set cooldown
|
||||||
|
toggleShowAssistants()
|
||||||
|
setSidebarHideCooldown(true)
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setSidebarHideCooldown(false)
|
||||||
|
// }, 10000) // 10 seconds cooldown
|
||||||
|
} else {
|
||||||
|
// When showing sidebar, no cooldown needed
|
||||||
|
toggleShowAssistants()
|
||||||
|
}
|
||||||
|
}, [showAssistants, toggleShowAssistants])
|
||||||
|
const handleToggleShowTopics = useCallback(() => {
|
||||||
|
if (showTopics) {
|
||||||
|
// When hiding sidebar, set cooldown
|
||||||
|
toggleShowTopics()
|
||||||
|
setSidebarHideCooldown(true)
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setSidebarHideCooldown(false)
|
||||||
|
// }, 10000) // 10 seconds cooldown
|
||||||
|
} else {
|
||||||
|
// When showing sidebar, no cooldown needed
|
||||||
|
toggleShowTopics()
|
||||||
|
}
|
||||||
|
}, [showTopics, toggleShowTopics])
|
||||||
|
|
||||||
|
useShortcut('toggle_show_assistants', handleToggleShowAssistants)
|
||||||
|
|
||||||
useShortcut('toggle_show_topics', () => {
|
useShortcut('toggle_show_topics', () => {
|
||||||
if (topicPosition === 'right') {
|
if (topicPosition === 'right') {
|
||||||
@ -60,7 +90,7 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
|||||||
{showAssistants && (
|
{showAssistants && (
|
||||||
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: 0 }}>
|
<NavbarLeft style={{ justifyContent: 'space-between', borderRight: 'none', padding: 0 }}>
|
||||||
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={0.8}>
|
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={0.8}>
|
||||||
<NavbarIcon onClick={toggleShowAssistants} style={{ marginLeft: isMac ? 16 : 0 }}>
|
<NavbarIcon onClick={handleToggleShowAssistants} style={{ marginLeft: isMac ? 16 : 0 }}>
|
||||||
<PanelLeftClose size={18} />
|
<PanelLeftClose size={18} />
|
||||||
</NavbarIcon>
|
</NavbarIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -73,11 +103,28 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
|||||||
)}
|
)}
|
||||||
<NavbarRight style={{ justifyContent: 'space-between', flex: 1 }} className="home-navbar-right">
|
<NavbarRight style={{ justifyContent: 'space-between', flex: 1 }} className="home-navbar-right">
|
||||||
<HStack alignItems="center">
|
<HStack alignItems="center">
|
||||||
{!showAssistants && (
|
{!showAssistants && !sidebarHideCooldown && (
|
||||||
|
<FloatingSidebar
|
||||||
|
activeAssistant={assistant}
|
||||||
|
setActiveAssistant={setActiveAssistant}
|
||||||
|
activeTopic={activeTopic}
|
||||||
|
setActiveTopic={setActiveTopic}
|
||||||
|
position={'left'}>
|
||||||
|
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={2}>
|
||||||
|
<NavbarIcon
|
||||||
|
onClick={() => toggleShowAssistants()}
|
||||||
|
style={{ marginRight: 8, marginLeft: isMac ? 4 : -12 }}>
|
||||||
|
<PanelRightClose size={18} />
|
||||||
|
</NavbarIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</FloatingSidebar>
|
||||||
|
)}
|
||||||
|
{!showAssistants && sidebarHideCooldown && (
|
||||||
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={0.8}>
|
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={0.8}>
|
||||||
<NavbarIcon
|
<NavbarIcon
|
||||||
onClick={() => toggleShowAssistants()}
|
onClick={() => toggleShowAssistants()}
|
||||||
style={{ marginRight: 8, marginLeft: isMac ? 4 : -12 }}>
|
style={{ marginRight: 8, marginLeft: isMac ? 4 : -12 }}
|
||||||
|
onMouseOut={() => setSidebarHideCooldown(false)}>
|
||||||
<PanelRightClose size={18} />
|
<PanelRightClose size={18} />
|
||||||
</NavbarIcon>
|
</NavbarIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -105,10 +152,33 @@ const HeaderNavbar: FC<Props> = ({ activeAssistant }) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</MinAppsPopover>
|
</MinAppsPopover>
|
||||||
)}
|
)}
|
||||||
{topicPosition === 'right' && (
|
{topicPosition === 'right' && !showTopics && !sidebarHideCooldown && (
|
||||||
<NarrowIcon onClick={toggleShowTopics}>
|
<FloatingSidebar
|
||||||
{showTopics ? <PanelRightClose size={18} /> : <PanelLeftClose size={18} />}
|
activeAssistant={assistant}
|
||||||
</NarrowIcon>
|
setActiveAssistant={setActiveAssistant}
|
||||||
|
activeTopic={activeTopic}
|
||||||
|
setActiveTopic={setActiveTopic}
|
||||||
|
position={'right'}>
|
||||||
|
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={2}>
|
||||||
|
<NavbarIcon onClick={() => toggleShowTopics()}>
|
||||||
|
<PanelLeftClose size={18} />
|
||||||
|
</NavbarIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</FloatingSidebar>
|
||||||
|
)}
|
||||||
|
{topicPosition === 'right' && !showTopics && sidebarHideCooldown && (
|
||||||
|
<Tooltip title={t('navbar.show_sidebar')} mouseEnterDelay={2}>
|
||||||
|
<NavbarIcon onClick={() => toggleShowTopics()} onMouseOut={() => setSidebarHideCooldown(false)}>
|
||||||
|
<PanelLeftClose size={18} />
|
||||||
|
</NavbarIcon>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{topicPosition === 'right' && showTopics && (
|
||||||
|
<Tooltip title={t('navbar.hide_sidebar')} mouseEnterDelay={2}>
|
||||||
|
<NavbarIcon onClick={() => handleToggleShowTopics()}>
|
||||||
|
<PanelRightClose size={18} />
|
||||||
|
</NavbarIcon>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</HStack>
|
</HStack>
|
||||||
</NavbarRight>
|
</NavbarRight>
|
||||||
|
|||||||
@ -20,18 +20,26 @@ interface Props {
|
|||||||
setActiveAssistant: (assistant: Assistant) => void
|
setActiveAssistant: (assistant: Assistant) => void
|
||||||
setActiveTopic: (topic: Topic) => void
|
setActiveTopic: (topic: Topic) => void
|
||||||
position: 'left' | 'right'
|
position: 'left' | 'right'
|
||||||
|
forceToSeeAllTab?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tab = 'assistants' | 'topic' | 'settings'
|
type Tab = 'assistants' | 'topic' | 'settings'
|
||||||
|
|
||||||
let _tab: any = ''
|
let _tab: any = ''
|
||||||
|
|
||||||
const HomeTabs: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssistant, setActiveTopic, position }) => {
|
const HomeTabs: FC<Props> = ({
|
||||||
|
activeAssistant,
|
||||||
|
activeTopic,
|
||||||
|
setActiveAssistant,
|
||||||
|
setActiveTopic,
|
||||||
|
position,
|
||||||
|
forceToSeeAllTab
|
||||||
|
}) => {
|
||||||
const { addAssistant } = useAssistants()
|
const { addAssistant } = useAssistants()
|
||||||
const [tab, setTab] = useState<Tab>(position === 'left' ? _tab || 'assistants' : 'topic')
|
const [tab, setTab] = useState<Tab>(position === 'left' ? _tab || 'assistants' : 'topic')
|
||||||
const { topicPosition } = useSettings()
|
const { topicPosition } = useSettings()
|
||||||
const { defaultAssistant } = useDefaultAssistant()
|
const { defaultAssistant } = useDefaultAssistant()
|
||||||
const { toggleShowTopics } = useShowTopics()
|
const { showTopics, toggleShowTopics } = useShowTopics()
|
||||||
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -86,20 +94,22 @@ const HomeTabs: FC<Props> = ({ activeAssistant, activeTopic, setActiveAssistant,
|
|||||||
if (position === 'right' && topicPosition === 'right' && tab === 'assistants') {
|
if (position === 'right' && topicPosition === 'right' && tab === 'assistants') {
|
||||||
setTab('topic')
|
setTab('topic')
|
||||||
}
|
}
|
||||||
if (position === 'left' && topicPosition === 'right' && tab !== 'assistants') {
|
if (position === 'left' && topicPosition === 'right' && forceToSeeAllTab != true && tab !== 'assistants') {
|
||||||
setTab('assistants')
|
setTab('assistants')
|
||||||
}
|
}
|
||||||
}, [position, tab, topicPosition])
|
}, [position, tab, topicPosition, forceToSeeAllTab])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container style={border} className="home-tabs">
|
<Container style={border} className="home-tabs">
|
||||||
{showTab && (
|
{(showTab || (forceToSeeAllTab == true && !showTopics)) && (
|
||||||
<Segmented
|
<Segmented
|
||||||
value={tab}
|
value={tab}
|
||||||
style={{ borderRadius: 16, paddingTop: 10, margin: '0 10px', gap: 2 }}
|
style={{ borderRadius: 16, paddingTop: 10, margin: '0 10px', gap: 2 }}
|
||||||
options={
|
options={
|
||||||
[
|
[
|
||||||
position === 'left' && topicPosition === 'left' ? assistantTab : undefined,
|
(position === 'left' && topicPosition === 'left') || (forceToSeeAllTab == true && position === 'left')
|
||||||
|
? assistantTab
|
||||||
|
: undefined,
|
||||||
{
|
{
|
||||||
label: t('common.topics'),
|
label: t('common.topics'),
|
||||||
value: 'topic'
|
value: 'topic'
|
||||||
@ -137,7 +147,6 @@ const Container = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: var(--assistants-width);
|
max-width: var(--assistants-width);
|
||||||
min-width: var(--assistants-width);
|
min-width: var(--assistants-width);
|
||||||
height: calc(100vh - var(--navbar-height));
|
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.collapsed {
|
.collapsed {
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export const EVENT_NAMES = {
|
|||||||
SHOW_CHAT_SETTINGS: 'SHOW_CHAT_SETTINGS',
|
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',
|
||||||
|
SWITCH_ASSISTANT: 'SWITCH_ASSISTANT',
|
||||||
NEW_CONTEXT: 'NEW_CONTEXT',
|
NEW_CONTEXT: 'NEW_CONTEXT',
|
||||||
NEW_BRANCH: 'NEW_BRANCH',
|
NEW_BRANCH: 'NEW_BRANCH',
|
||||||
COPY_TOPIC_IMAGE: 'COPY_TOPIC_IMAGE',
|
COPY_TOPIC_IMAGE: 'COPY_TOPIC_IMAGE',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user