@@ -3100,26 +3100,19 @@ function ChatViewContent(props: ChatViewProps) {
31003100 threadKey === routeThreadKey ? null : routeThreadKey ,
31013101 ) ;
31023102 } ;
3103- const closeRightPanelSurface = useCallback (
3104- ( surface : RightPanelSurface ) => {
3103+ const cleanupRightPanelSurfaces = useCallback (
3104+ ( surfaces : readonly RightPanelSurface [ ] ) => {
31053105 if ( ! activeThreadRef ) return ;
3106- if ( surface . kind === "preview" && surface . resourceId ) {
3107- usePreviewStateStore . getState ( ) . removeSession ( activeThreadRef , surface . resourceId ) ;
3108- const api = readEnvironmentApi ( activeThreadRef . environmentId ) ;
3109- void api ?. preview
3110- . close ( { threadId : activeThreadRef . threadId , tabId : surface . resourceId } )
3111- . catch ( ( ) => undefined ) ;
3112- }
3113- useRightPanelStore . getState ( ) . closeSurface ( activeThreadRef , surface . id ) ;
3114- const nextActiveSurface = selectActiveRightPanelSurface (
3115- useRightPanelStore . getState ( ) . byThreadKey ,
3116- activeThreadRef ,
3117- ) ;
3118- if ( nextActiveSurface ?. kind === "preview" && nextActiveSurface . resourceId ) {
3119- usePreviewStateStore . getState ( ) . setActiveTab ( activeThreadRef , nextActiveSurface . resourceId ) ;
3120- }
3121- if ( surface . kind === "terminal" ) {
3122- const api = readEnvironmentApi ( activeThreadRef . environmentId ) ;
3106+
3107+ const api = readEnvironmentApi ( activeThreadRef . environmentId ) ;
3108+ for ( const surface of surfaces ) {
3109+ if ( surface . kind === "preview" && surface . resourceId ) {
3110+ usePreviewStateStore . getState ( ) . removeSession ( activeThreadRef , surface . resourceId ) ;
3111+ void api ?. preview
3112+ . close ( { threadId : activeThreadRef . threadId , tabId : surface . resourceId } )
3113+ . catch ( ( ) => undefined ) ;
3114+ }
3115+ if ( surface . kind !== "terminal" ) continue ;
31233116 for ( const terminalId of surface . terminalIds ) {
31243117 void api ?. terminal
31253118 . close ( {
@@ -3130,7 +3123,8 @@ function ChatViewContent(props: ChatViewProps) {
31303123 . catch ( ( ) => undefined ) ;
31313124 }
31323125 }
3133- if ( surface . kind === "diff" && diffOpen ) {
3126+
3127+ if ( diffOpen && surfaces . some ( ( surface ) => surface . kind === "diff" ) ) {
31343128 void navigate ( {
31353129 to : "/$environmentId/$threadId" ,
31363130 params : { environmentId, threadId } ,
@@ -3141,6 +3135,93 @@ function ChatViewContent(props: ChatViewProps) {
31413135 } ,
31423136 [ activeThreadRef , diffOpen , environmentId , navigate , threadId ] ,
31433137 ) ;
3138+ const syncActivePreviewSurface = useCallback ( ( ) => {
3139+ if ( ! activeThreadRef ) return ;
3140+ const nextActiveSurface = selectActiveRightPanelSurface (
3141+ useRightPanelStore . getState ( ) . byThreadKey ,
3142+ activeThreadRef ,
3143+ ) ;
3144+ if ( nextActiveSurface ?. kind === "preview" && nextActiveSurface . resourceId ) {
3145+ usePreviewStateStore . getState ( ) . setActiveTab ( activeThreadRef , nextActiveSurface . resourceId ) ;
3146+ }
3147+ } , [ activeThreadRef ] ) ;
3148+ const closeRightPanelSurface = useCallback (
3149+ ( surface : RightPanelSurface ) => {
3150+ if ( ! activeThreadRef ) return ;
3151+ cleanupRightPanelSurfaces ( [ surface ] ) ;
3152+ useRightPanelStore . getState ( ) . closeSurface ( activeThreadRef , surface . id ) ;
3153+ syncActivePreviewSurface ( ) ;
3154+ } ,
3155+ [ activeThreadRef , cleanupRightPanelSurfaces , syncActivePreviewSurface ] ,
3156+ ) ;
3157+ const closeOtherRightPanelSurfaces = useCallback (
3158+ ( surface : RightPanelSurface ) => {
3159+ if ( ! activeThreadRef ) return ;
3160+ const surfaces = rightPanelState . surfaces . filter ( ( entry ) => entry . id !== surface . id ) ;
3161+ cleanupRightPanelSurfaces ( surfaces ) ;
3162+ useRightPanelStore . getState ( ) . closeOtherSurfaces ( activeThreadRef , surface . id ) ;
3163+ syncActivePreviewSurface ( ) ;
3164+ } ,
3165+ [
3166+ activeThreadRef ,
3167+ cleanupRightPanelSurfaces ,
3168+ rightPanelState . surfaces ,
3169+ syncActivePreviewSurface ,
3170+ ] ,
3171+ ) ;
3172+ const closeRightPanelSurfacesToRight = useCallback (
3173+ ( surface : RightPanelSurface ) => {
3174+ if ( ! activeThreadRef ) return ;
3175+ const surfaceIndex = rightPanelState . surfaces . findIndex ( ( entry ) => entry . id === surface . id ) ;
3176+ if ( surfaceIndex < 0 ) return ;
3177+ const surfaces = rightPanelState . surfaces . slice ( surfaceIndex + 1 ) ;
3178+ cleanupRightPanelSurfaces ( surfaces ) ;
3179+ useRightPanelStore . getState ( ) . closeSurfacesToRight ( activeThreadRef , surface . id ) ;
3180+ syncActivePreviewSurface ( ) ;
3181+ } ,
3182+ [
3183+ activeThreadRef ,
3184+ cleanupRightPanelSurfaces ,
3185+ rightPanelState . surfaces ,
3186+ syncActivePreviewSurface ,
3187+ ] ,
3188+ ) ;
3189+ const closeAllRightPanelSurfaces = useCallback ( ( ) => {
3190+ if ( ! activeThreadRef ) return ;
3191+ cleanupRightPanelSurfaces ( rightPanelState . surfaces ) ;
3192+ useRightPanelStore . getState ( ) . closeAllSurfaces ( activeThreadRef ) ;
3193+ } , [ activeThreadRef , cleanupRightPanelSurfaces , rightPanelState . surfaces ] ) ;
3194+ const copyRightPanelFilePath = useCallback ( ( relativePath : string ) => {
3195+ if ( typeof window === "undefined" || ! navigator . clipboard ?. writeText ) {
3196+ toastManager . add (
3197+ stackedThreadToast ( {
3198+ type : "error" ,
3199+ title : "Failed to copy path" ,
3200+ description : "Clipboard API unavailable." ,
3201+ } ) ,
3202+ ) ;
3203+ return ;
3204+ }
3205+
3206+ void navigator . clipboard . writeText ( relativePath ) . then (
3207+ ( ) => {
3208+ toastManager . add ( {
3209+ type : "success" ,
3210+ title : "Path copied" ,
3211+ description : relativePath ,
3212+ } ) ;
3213+ } ,
3214+ ( error ) => {
3215+ toastManager . add (
3216+ stackedThreadToast ( {
3217+ type : "error" ,
3218+ title : "Failed to copy path" ,
3219+ description : error instanceof Error ? error . message : "An error occurred." ,
3220+ } ) ,
3221+ ) ;
3222+ } ,
3223+ ) ;
3224+ } , [ ] ) ;
31443225 const persistThreadSettingsForNextTurn = useCallback (
31453226 async ( input : {
31463227 threadId : ThreadId ;
@@ -4851,6 +4932,10 @@ function ChatViewContent(props: ChatViewProps) {
48514932 terminalLabelsById = { activeTerminalLabelsById }
48524933 onActivate = { activateRightPanelSurface }
48534934 onCloseSurface = { closeRightPanelSurface }
4935+ onCloseOtherSurfaces = { closeOtherRightPanelSurfaces }
4936+ onCloseSurfacesToRight = { closeRightPanelSurfacesToRight }
4937+ onCloseAllSurfaces = { closeAllRightPanelSurfaces }
4938+ onCopyFilePath = { copyRightPanelFilePath }
48544939 onAddBrowser = { createBrowserSurface }
48554940 onAddTerminal = { addTerminalSurface }
48564941 onAddDiff = { addDiffSurface }
@@ -4929,6 +5014,10 @@ function ChatViewContent(props: ChatViewProps) {
49295014 terminalLabelsById = { activeTerminalLabelsById }
49305015 onActivate = { activateRightPanelSurface }
49315016 onCloseSurface = { closeRightPanelSurface }
5017+ onCloseOtherSurfaces = { closeOtherRightPanelSurfaces }
5018+ onCloseSurfacesToRight = { closeRightPanelSurfacesToRight }
5019+ onCloseAllSurfaces = { closeAllRightPanelSurfaces }
5020+ onCopyFilePath = { copyRightPanelFilePath }
49325021 onAddBrowser = { createBrowserSurface }
49335022 onAddTerminal = { addTerminalSurface }
49345023 onAddDiff = { addDiffSurface }
0 commit comments