22// SPDX-License-Identifier: Apache-2.0
33
44import { WaveAIModel } from "@/app/aipanel/waveai-model" ;
5+ import { focusManager } from "@/app/store/focusManager" ;
56import {
67 atoms ,
78 createBlock ,
@@ -18,7 +19,7 @@ import {
1819 replaceBlock ,
1920 WOS ,
2021} from "@/app/store/global" ;
21- import { focusManager } from "@/app/store/focusManager " ;
22+ import { TabBarModel } from "@/app/tab/tabbar-model " ;
2223import { WorkspaceLayoutModel } from "@/app/workspace/workspace-layout-model" ;
2324import { deleteLayoutModelForTab , getLayoutModelForStaticTab , NavigateDirection } from "@/layout/index" ;
2425import * as keyutil from "@/util/keyutil" ;
@@ -104,23 +105,80 @@ function shouldDispatchToBlock(e: WaveKeyboardEvent): boolean {
104105 return true ;
105106}
106107
107- function genericClose ( ) {
108- const ws = globalStore . get ( atoms . workspace ) ;
108+ function getStaticTabBlockCount ( ) : number {
109109 const tabId = globalStore . get ( atoms . staticTabId ) ;
110110 const tabORef = WOS . makeORef ( "tab" , tabId ) ;
111111 const tabAtom = WOS . getWaveObjectAtom < Tab > ( tabORef ) ;
112112 const tabData = globalStore . get ( tabAtom ) ;
113- if ( tabData == null ) {
113+ return tabData ?. blockids ?. length ?? 0 ;
114+ }
115+
116+ function isStaticTabPinned ( ) : boolean {
117+ const ws = globalStore . get ( atoms . workspace ) ;
118+ const tabId = globalStore . get ( atoms . staticTabId ) ;
119+ return ws . pinnedtabids ?. includes ( tabId ) ?? false ;
120+ }
121+
122+ function simpleCloseStaticTab ( ) {
123+ const ws = globalStore . get ( atoms . workspace ) ;
124+ const tabId = globalStore . get ( atoms . staticTabId ) ;
125+ getApi ( ) . closeTab ( ws . oid , tabId ) ;
126+ deleteLayoutModelForTab ( tabId ) ;
127+ }
128+
129+ function uxCloseBlock ( blockId : string ) {
130+ if ( isStaticTabPinned ( ) && getStaticTabBlockCount ( ) === 1 ) {
131+ TabBarModel . getInstance ( ) . jiggleActivePinnedTab ( ) ;
132+ return ;
133+ }
134+
135+ const workspaceLayoutModel = WorkspaceLayoutModel . getInstance ( ) ;
136+ const isAIPanelOpen = workspaceLayoutModel . getAIPanelVisible ( ) ;
137+ if ( isAIPanelOpen && getStaticTabBlockCount ( ) === 1 ) {
138+ const aiModel = WaveAIModel . getInstance ( ) ;
139+ const shouldSwitchToAI = ! aiModel . isChatEmpty || aiModel . hasNonEmptyInput ( ) ;
140+ if ( shouldSwitchToAI ) {
141+ replaceBlock ( blockId , { meta : { view : "launcher" } } , false ) ;
142+ setTimeout ( ( ) => WaveAIModel . getInstance ( ) . focusInput ( ) , 50 ) ;
143+ return ;
144+ }
145+ }
146+ const layoutModel = getLayoutModelForStaticTab ( ) ;
147+ const node = layoutModel . getNodeByBlockId ( blockId ) ;
148+ if ( node ) {
149+ fireAndForget ( ( ) => layoutModel . closeNode ( node . id ) ) ;
150+ }
151+ }
152+
153+ function genericClose ( ) {
154+ const focusType = focusManager . getFocusType ( ) ;
155+ if ( focusType === "waveai" ) {
156+ WorkspaceLayoutModel . getInstance ( ) . setAIPanelVisible ( false ) ;
114157 return ;
115158 }
116- if ( ws . pinnedtabids ?. includes ( tabId ) && tabData . blockids ?. length == 1 ) {
117- // don't allow closing the last block in a pinned tab
159+ if ( isStaticTabPinned ( ) && getStaticTabBlockCount ( ) = == 1 ) {
160+ TabBarModel . getInstance ( ) . jiggleActivePinnedTab ( ) ;
118161 return ;
119162 }
120- if ( tabData . blockids == null || tabData . blockids . length == 0 ) {
121- // close tab
122- getApi ( ) . closeTab ( ws . oid , tabId ) ;
123- deleteLayoutModelForTab ( tabId ) ;
163+
164+ const workspaceLayoutModel = WorkspaceLayoutModel . getInstance ( ) ;
165+ const isAIPanelOpen = workspaceLayoutModel . getAIPanelVisible ( ) ;
166+ if ( isAIPanelOpen && getStaticTabBlockCount ( ) === 1 ) {
167+ const aiModel = WaveAIModel . getInstance ( ) ;
168+ const shouldSwitchToAI = ! aiModel . isChatEmpty || aiModel . hasNonEmptyInput ( ) ;
169+ if ( shouldSwitchToAI ) {
170+ const layoutModel = getLayoutModelForStaticTab ( ) ;
171+ const focusedNode = globalStore . get ( layoutModel . focusedNode ) ;
172+ if ( focusedNode ) {
173+ replaceBlock ( focusedNode . data . blockId , { meta : { view : "launcher" } } , false ) ;
174+ setTimeout ( ( ) => WaveAIModel . getInstance ( ) . focusInput ( ) , 50 ) ;
175+ return ;
176+ }
177+ }
178+ }
179+ const blockCount = getStaticTabBlockCount ( ) ;
180+ if ( blockCount === 0 ) {
181+ simpleCloseStaticTab ( ) ;
124182 return ;
125183 }
126184 const layoutModel = getLayoutModelForStaticTab ( ) ;
@@ -427,16 +485,11 @@ function registerGlobalKeys() {
427485 return true ;
428486 } ) ;
429487 globalKeyMap . set ( "Cmd:Shift:w" , ( ) => {
430- const tabId = globalStore . get ( atoms . staticTabId ) ;
431- const ws = globalStore . get ( atoms . workspace ) ;
432- if ( ws . pinnedtabids ?. includes ( tabId ) ) {
433- // switch to first unpinned tab if it exists (for close spamming)
434- if ( ws . tabids != null && ws . tabids . length > 0 ) {
435- getApi ( ) . setActiveTab ( ws . tabids [ 0 ] ) ;
436- }
488+ if ( isStaticTabPinned ( ) ) {
489+ TabBarModel . getInstance ( ) . jiggleActivePinnedTab ( ) ;
437490 return true ;
438491 }
439- getApi ( ) . closeTab ( ws . oid , tabId ) ;
492+ simpleCloseStaticTab ( ) ;
440493 return true ;
441494 } ) ;
442495 globalKeyMap . set ( "Cmd:m" , ( ) => {
@@ -468,11 +521,15 @@ function registerGlobalKeys() {
468521 if ( blockId == null ) {
469522 return true ;
470523 }
471- replaceBlock ( blockId , {
472- meta : {
473- view : "launcher" ,
524+ replaceBlock (
525+ blockId ,
526+ {
527+ meta : {
528+ view : "launcher" ,
529+ } ,
474530 } ,
475- } ) ;
531+ true
532+ ) ;
476533 return true ;
477534 } ) ;
478535 globalKeyMap . set ( "Cmd:g" , ( ) => {
@@ -604,4 +661,5 @@ export {
604661 registerGlobalKeys ,
605662 tryReinjectKey ,
606663 unsetControlShift ,
664+ uxCloseBlock ,
607665} ;
0 commit comments