diff --git a/app/assets/javascripts/super_sidebar/constants.js b/app/assets/javascripts/super_sidebar/constants.js index 42e5bfc5ebfc268d0cd5a6bafad9f0b9c8a51148..a8cc4b5991bbc7a957e282b99f279acfae3af81c 100644 --- a/app/assets/javascripts/super_sidebar/constants.js +++ b/app/assets/javascripts/super_sidebar/constants.js @@ -23,10 +23,17 @@ export const sidebarState = Vue.observable({ wasHoverPeek: false, }); +export const CHAT_MODES = { + CLASSIC: 'classic', + AGENTIC: 'agentic', +}; + export const duoChatGlobalState = Vue.observable({ commands: [], isShown: false, isAgenticChatShown: false, + chatMode: CHAT_MODES.CLASSIC, // CHAT_MODES.CLASSIC or CHAT_MODES.AGENTIC - single source of truth for chat mode + activeTab: null, // For embedded mode: which tab is active in the AI panel ('chat', 'history', etc.) }); export const SUPER_SIDEBAR_PEEK_OPEN_DELAY = 200; diff --git a/ee/app/assets/javascripts/ai/components/ai_panel.vue b/ee/app/assets/javascripts/ai/components/ai_panel.vue index e20e8efff677629e3a79a76170758710cff6acf1..3462d29ba874b4efafe9e3899880551c7b267aa2 100644 --- a/ee/app/assets/javascripts/ai/components/ai_panel.vue +++ b/ee/app/assets/javascripts/ai/components/ai_panel.vue @@ -4,7 +4,9 @@ import { __ } from '~/locale'; import AgentSessionsRoot from '~/vue_shared/spa/components/spa_root.vue'; import { AGENTS_PLATFORM_SHOW_ROUTE } from 'ee/ai/duo_agents_platform/router/constants'; import { formatAgentFlowName } from 'ee/ai/duo_agents_platform/utils'; +import { CHAT_MODES } from 'ee/ai/tanuki_bot/constants'; import Cookies from '~/lib/utils/cookies'; +import { duoChatGlobalState } from '~/super_sidebar/constants'; import AiContentContainer from './content_container.vue'; import NavigationRail from './navigation_rail.vue'; @@ -55,30 +57,51 @@ export default { }, }, data() { + // Initialize global state from cookie if not already set + if (duoChatGlobalState.activeTab === null) { + duoChatGlobalState.activeTab = Cookies.get(ACTIVE_TAB_KEY) || undefined; + } + return { - activeTab: Cookies.get(ACTIVE_TAB_KEY), isDesktop: GlBreakpointInstance.isDesktop(), + duoChatGlobalState, }; }, computed: { + activeTab() { + return this.duoChatGlobalState.activeTab; + }, + isAgenticMode() { + return this.duoChatGlobalState.chatMode === CHAT_MODES.AGENTIC; + }, + currentChatComponent() { + return this.isAgenticMode + ? this.chatConfiguration.agenticComponent + : this.chatConfiguration.classicComponent; + }, + currentChatTitle() { + return this.isAgenticMode + ? this.chatConfiguration.agenticTitle + : this.chatConfiguration.classicTitle; + }, currentTabComponent() { switch (this.activeTab) { case 'chat': return { - title: this.chatConfiguration.title, - component: this.chatConfiguration.component, + title: this.currentChatTitle, + component: this.currentChatComponent, props: { mode: 'active', ...this.chatConfiguration.defaultProps }, }; case 'new': return { title: __('New Chat'), - component: this.chatConfiguration.component, + component: this.currentChatComponent, props: { mode: 'new', ...this.chatConfiguration.defaultProps }, }; case 'history': return { title: __('History'), - component: this.chatConfiguration.component, + component: this.currentChatComponent, props: { mode: 'history', ...this.chatConfiguration.defaultProps }, }; case 'suggestions': @@ -124,7 +147,9 @@ export default { } }, setActiveTab(value) { - this.activeTab = value; + // Update global state (will trigger Vue reactivity) + this.duoChatGlobalState.activeTab = value; + // Also update cookie for persistence across page loads if (value) { Cookies.set(ACTIVE_TAB_KEY, value); } else { diff --git a/ee/app/assets/javascripts/ai/components/content_container.vue b/ee/app/assets/javascripts/ai/components/content_container.vue index 8a2637306757f054e4519f23aec04c53d74f34d7..4b80aee13e11b0409848cf6ee5d19844cded8c5e 100644 --- a/ee/app/assets/javascripts/ai/components/content_container.vue +++ b/ee/app/assets/javascripts/ai/components/content_container.vue @@ -1,5 +1,6 @@