@@ -139,6 +139,8 @@ export class PatchWidget extends UI.Widget.Widget {
139139 // Whether the user completed first run experience dialog or not.
140140 #aiPatchingFreCompletedSetting =
141141 Common . Settings . Settings . instance ( ) . createSetting ( 'ai-assistance-patching-fre-completed' , false ) ;
142+ #projectIdSetting =
143+ Common . Settings . Settings . instance ( ) . createSetting ( 'ai-assistance-patching-selected-project-id' , '' ) ;
142144 #view: View ;
143145 #viewOutput: ViewOutput = { } ;
144146 #aidaClient: Host . AidaClient . AidaClient ;
@@ -156,6 +158,7 @@ export class PatchWidget extends UI.Widget.Widget {
156158 } ) {
157159 super ( false , false , element ) ;
158160 this . #aidaClient = opts ?. aidaClient ?? new Host . AidaClient . AidaClient ( ) ;
161+
159162 // clang-format off
160163 this . #view = view ?? ( ( input , output , target ) => {
161164 if ( ! input . changeSummary ) {
@@ -257,17 +260,19 @@ export class PatchWidget extends UI.Widget.Widget {
257260
258261 return html `
259262 < div class ="footer ">
260- < div class ="change-workspace ">
261- < div class ="selected-folder ">
262- < devtools-icon .name =${ 'folder' } > </ devtools-icon > < span title =${ input . projectPath } > ${ input . projectName } </ span >
263+ ${ input . projectName ? html `
264+ < div class ="change-workspace ">
265+ < div class ="selected-folder ">
266+ < devtools-icon .name =${ 'folder' } > </ devtools-icon > < span title =${ input . projectPath } > ${ input . projectName } </ span >
267+ </ div >
268+ < devtools-button
269+ @click =${ input . onChangeWorkspaceClick }
270+ .jslogContext =${ 'change-workspace' }
271+ .variant=${ Buttons . Button . Variant . TEXT } >
272+ ${ lockedString ( UIStringsNotTranslate . change ) }
273+ </ devtools-button >
263274 </ div >
264- < devtools-button
265- @click =${ input . onChangeWorkspaceClick }
266- .jslogContext =${ 'change-workspace' }
267- .variant=${ Buttons . Button . Variant . TEXT } >
268- ${ lockedString ( UIStringsNotTranslate . change ) }
269- </ devtools-button >
270- </ div >
275+ ` : nothing }
271276 < div class ="apply-to-workspace-container ">
272277 ${ input . patchSuggestionLoading ? html `
273278 < div class ="loading-text-container ">
@@ -333,22 +338,6 @@ export class PatchWidget extends UI.Widget.Widget {
333338 this . requestUpdate ( ) ;
334339 }
335340
336- #onChangeWorkspaceClick( ) : void {
337- const dialog = new UI . Dialog . Dialog ( 'select-workspace' ) ;
338- dialog . setMaxContentSize ( new UI . Geometry . Size ( 384 , 340 ) ) ;
339- dialog . setSizeBehavior ( UI . GlassPane . SizeBehavior . SET_EXACT_WIDTH_MAX_HEIGHT ) ;
340- dialog . setDimmed ( true ) ;
341-
342- const handleProjectSelected = ( project : Workspace . Workspace . Project ) : void => {
343- this . #project = project ;
344- this . requestUpdate ( ) ;
345- } ;
346-
347- new SelectWorkspaceDialog ( { dialog, handleProjectSelected, currentProject : this . #project} )
348- . show ( dialog . contentElement ) ;
349- dialog . show ( ) ;
350- }
351-
352341 #onLearnMoreTooltipClick( ) : void {
353342 this . #viewOutput. tooltipRef ?. value ?. hidePopover ( ) ;
354343 void UI . ViewManager . ViewManager . instance ( ) . showView ( 'chrome-ai' ) ;
@@ -373,7 +362,7 @@ export class PatchWidget extends UI.Widget.Widget {
373362 } ,
374363 onDiscard : this . #onDiscard. bind ( this ) ,
375364 onSaveAll : this . #onSaveAll. bind ( this ) ,
376- onChangeWorkspaceClick : this . #onChangeWorkspaceClick . bind ( this ) ,
365+ onChangeWorkspaceClick : this . #showSelectWorkspaceDialog . bind ( this , { applyPatch : false } ) ,
377366 } ,
378367 this . #viewOutput, this . contentElement ) ;
379368 }
@@ -383,8 +372,7 @@ export class PatchWidget extends UI.Widget.Widget {
383372 this . #selectDefaultProject( ) ;
384373
385374 if ( isAiAssistancePatchingEnabled ( ) ) {
386- this . #workspace. addEventListener ( Workspace . Workspace . Events . ProjectAdded , this . #onProjectAddedOrRemoved, this ) ;
387- this . #workspace. addEventListener ( Workspace . Workspace . Events . ProjectRemoved , this . #onProjectAddedOrRemoved, this ) ;
375+ this . #workspace. addEventListener ( Workspace . Workspace . Events . ProjectRemoved , this . #onProjectRemoved, this ) ;
388376
389377 // @ts -expect-error temporary global function for local testing.
390378 window . aiAssistanceTestPatchPrompt = async ( changeSummary : string ) => {
@@ -395,9 +383,7 @@ export class PatchWidget extends UI.Widget.Widget {
395383
396384 override willHide ( ) : void {
397385 if ( isAiAssistancePatchingEnabled ( ) ) {
398- this . #workspace. removeEventListener ( Workspace . Workspace . Events . ProjectAdded , this . #onProjectAddedOrRemoved, this ) ;
399- this . #workspace. removeEventListener (
400- Workspace . Workspace . Events . ProjectRemoved , this . #onProjectAddedOrRemoved, this ) ;
386+ this . #workspace. removeEventListener ( Workspace . Workspace . Events . ProjectRemoved , this . #onProjectRemoved, this ) ;
401387 }
402388 }
403389
@@ -443,41 +429,42 @@ export class PatchWidget extends UI.Widget.Widget {
443429 }
444430
445431 #selectDefaultProject( ) : void {
446- if ( isAiAssistancePatchingEnabled ( ) ) {
447- // TODO: this is temporary code that should be replaced with
448- // workflow selection flow. For now it picks the first Workspace
449- // project that is not Snippets.
450- const projects = this . #workspace. projectsForType ( Workspace . Workspace . projectTypes . FileSystem ) ;
432+ const project = this . #workspace. project ( this . #projectIdSetting. get ( ) ) ;
433+ if ( project ) {
434+ this . #project = project ;
435+ } else {
451436 this . #project = undefined ;
452- for ( const project of projects ) {
453- // This is for TypeScript to narrow the types. projectsForType()
454- // probably only returns instances of
455- // Persistence.FileSystemWorkspaceBinding.FileSystem.
456- if ( ! ( project instanceof Persistence . FileSystemWorkspaceBinding . FileSystem ) ) {
457- continue ;
458- }
459- if ( project . fileSystem ( ) . type ( ) !== Persistence . PlatformFileSystem . PlatformFileSystemType . WORKSPACE_PROJECT ) {
460- continue ;
461- }
462- this . #project = project ;
463- this . requestUpdate ( ) ;
464- break ;
465- }
437+ this . #projectIdSetting. set ( '' ) ;
466438 }
439+ this . requestUpdate ( ) ;
467440 }
468441
469- #onProjectAddedOrRemoved( ) : void {
470- this . #selectDefaultProject( ) ;
442+ #onProjectRemoved( ) : void {
443+ if ( this . #project && ! this . #workspace. project ( this . #project. id ( ) ) ) {
444+ this . #projectIdSetting. set ( '' ) ;
445+ this . #project = undefined ;
446+ this . requestUpdate ( ) ;
447+ }
448+ }
449+
450+ #showSelectWorkspaceDialog( options : { applyPatch : boolean } = { applyPatch : false } ) : void {
451+ const onProjectSelected = ( project : Workspace . Workspace . Project ) : void => {
452+ this . #project = project ;
453+ this . #projectIdSetting. set ( project . id ( ) ) ;
454+ if ( options . applyPatch ) {
455+ void this . #applyPatchAndUpdateUI( ) ;
456+ } else {
457+ this . requestUpdate ( ) ;
458+ }
459+ } ;
460+
461+ SelectWorkspaceDialog . show ( onProjectSelected , this . #project) ;
471462 }
472463
473464 async #onApplyToWorkspace( ) : Promise < void > {
474465 if ( ! isAiAssistancePatchingEnabled ( ) ) {
475466 return ;
476467 }
477- const changeSummary = this . changeSummary ;
478- if ( ! changeSummary ) {
479- throw new Error ( 'Change summary does not exist' ) ;
480- }
481468
482469 // Show the FRE dialog if needed and only continue when
483470 // the user accepted the disclaimer.
@@ -486,6 +473,19 @@ export class PatchWidget extends UI.Widget.Widget {
486473 return ;
487474 }
488475
476+ if ( this . #project) {
477+ await this . #applyPatchAndUpdateUI( ) ;
478+ } else {
479+ this . #showSelectWorkspaceDialog( { applyPatch : true } ) ;
480+ }
481+ }
482+
483+ async #applyPatchAndUpdateUI( ) : Promise < void > {
484+ const changeSummary = this . changeSummary ;
485+ if ( ! changeSummary ) {
486+ throw new Error ( 'Change summary does not exist' ) ;
487+ }
488+
489489 this . #patchSuggestionLoading = true ;
490490 this . requestUpdate ( ) ;
491491 const { response, processedFiles} = await this . #applyPatch( changeSummary ) ;
0 commit comments