@@ -11,8 +11,8 @@ import { AbstractExtensionService } from 'vs/workbench/services/extensions/commo
1111import * as nls from 'vs/nls' ;
1212import { runWhenIdle } from 'vs/base/common/async' ;
1313import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService' ;
14- import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement' ;
15- import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement' ;
14+ import { IExtensionManagementService , IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement' ;
15+ import { IWorkbenchExtensionEnablementService , EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement' ;
1616import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
1717import { IInitDataProvider , RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient' ;
1818import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService' ;
@@ -41,6 +41,7 @@ import { Action } from 'vs/base/common/actions';
4141import { SyncActionDescriptor } from 'vs/platform/actions/common/actions' ;
4242import { Registry } from 'vs/platform/registry/common/platform' ;
4343import { Extensions as ActionExtensions , IWorkbenchActionRegistry } from 'vs/workbench/common/actions' ;
44+ import { getRemoteName } from 'vs/platform/remote/common/remoteHosts' ;
4445
4546class DeltaExtensionsQueueItem {
4647 constructor (
@@ -73,7 +74,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
7374 @IElectronService private readonly _electronService : IElectronService ,
7475 @IHostService private readonly _hostService : IHostService ,
7576 @IElectronEnvironmentService private readonly _electronEnvironmentService : IElectronEnvironmentService ,
76- @IRemoteExplorerService private readonly _remoteExplorerService : IRemoteExplorerService
77+ @IRemoteExplorerService private readonly _remoteExplorerService : IRemoteExplorerService ,
78+ @IExtensionGalleryService private readonly _extensionGalleryService : IExtensionGalleryService ,
7779 ) {
7880 super (
7981 instantiationService ,
@@ -455,13 +457,16 @@ export class ExtensionService extends AbstractExtensionService implements IExten
455457 try {
456458 resolvedAuthority = await extensionHost . resolveAuthority ( remoteAuthority ) ;
457459 } catch ( err ) {
458- console . error ( err ) ;
459- const plusIndex = remoteAuthority . indexOf ( '+' ) ;
460- const authorityFriendlyName = plusIndex > 0 ? remoteAuthority . substr ( 0 , plusIndex ) : remoteAuthority ;
461- if ( ! RemoteAuthorityResolverError . isHandledNotAvailable ( err ) ) {
462- this . _notificationService . notify ( { severity : Severity . Error , message : nls . localize ( 'resolveAuthorityFailure' , "Resolving the authority `{0}` failed" , authorityFriendlyName ) } ) ;
460+ const remoteName = getRemoteName ( remoteAuthority ) ;
461+ if ( RemoteAuthorityResolverError . isNoResolverFound ( err ) ) {
462+ this . _handleNoResolverFound ( remoteName ) ;
463463 } else {
464- console . log ( `Not showing a notification for the error` ) ;
464+ console . log ( err ) ;
465+ if ( RemoteAuthorityResolverError . isHandledNotAvailable ( err ) ) {
466+ console . log ( `Not showing a notification for the error` ) ;
467+ } else {
468+ this . _notificationService . notify ( { severity : Severity . Error , message : nls . localize ( 'resolveAuthorityFailure' , "Resolving the authority `{0}` failed" , remoteName ) } ) ;
469+ }
465470 }
466471
467472 this . _remoteAuthorityResolverService . setResolvedAuthorityError ( remoteAuthority , err ) ;
@@ -578,6 +583,70 @@ export class ExtensionService extends AbstractExtensionService implements IExten
578583 this . _electronService . closeWindow ( ) ;
579584 }
580585 }
586+
587+ private async _handleNoResolverFound ( remoteName : string ) : Promise < void > {
588+ const recommendation = this . _productService . remoteExtensionTips ?. [ remoteName ] ;
589+ if ( ! recommendation ) {
590+ return ;
591+ }
592+ const resolverExtensionId = recommendation . extensionId ;
593+ const installedExtensions = await this . _extensionManagementService . getInstalled ( ) ;
594+ const extension = installedExtensions . filter ( e => e . identifier . id === resolverExtensionId ) [ 0 ] ;
595+ if ( extension ) {
596+ if ( ! await this . _extensionEnablementService . isEnabled ( extension ) ) {
597+ const message = nls . localize ( 'enableResolver' , "Extension '{0}' is required to open the remote window. Ok to enable the extension?" , recommendation . friendlyName ) ;
598+ this . _notificationService . prompt ( Severity . Info , message ,
599+ [ {
600+ label : nls . localize ( 'enable' , 'Enable' ) ,
601+ run : async ( ) => {
602+ this . _extensionEnablementService . setEnablement ( [ extension ] , EnablementState . EnabledGlobally ) ;
603+ }
604+ } ] ,
605+ { sticky : true }
606+ ) ;
607+ }
608+ } else {
609+ // Install the Extension and reload the window to handle.
610+ const message = nls . localize ( 'installResolver' , "Extension '{0}' is required to open the remote window. Ok to install the extension?" , recommendation . friendlyName ) ;
611+ this . _notificationService . prompt ( Severity . Info , message ,
612+ [ {
613+ label : nls . localize ( 'install' , 'Install and Reload' ) ,
614+ run : async ( ) => {
615+ /* __GDPR__
616+ "remoteExtensionRecommendations:popup" : {
617+ "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
618+ "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
619+ }
620+ */
621+ this . _telemetryService . publicLog ( 'remoteExtensionRecommendations:popup' , { userReaction : 'install' , extensionId : resolverExtensionId } ) ;
622+
623+ const galleryExtension = await this . _extensionGalleryService . getCompatibleExtension ( { id : resolverExtensionId } ) ;
624+ if ( galleryExtension ) {
625+ await this . _extensionManagementService . installFromGallery ( galleryExtension ) ;
626+ this . _hostService . reload ( ) ;
627+ } else {
628+ this . _notificationService . error ( nls . localize ( 'resolverExtensionNotFound' , "`{0}` not found on marketplace" ) ) ;
629+ }
630+
631+ }
632+ } ] ,
633+ {
634+ sticky : true ,
635+ onCancel : ( ) => {
636+ /* __GDPR__
637+ "remoteExtensionRecommendations:popup" : {
638+ "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
639+ "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }
640+ }
641+ */
642+ this . _telemetryService . publicLog ( 'remoteExtensionRecommendations:popup' , { userReaction : 'cancelled' , extensionId : resolverExtensionId } ) ;
643+ }
644+ }
645+ ) ;
646+
647+ }
648+
649+ }
581650}
582651
583652function remove ( arr : IExtensionDescription [ ] , predicate : ( item : IExtensionDescription ) => boolean ) : IExtensionDescription [ ] ;
0 commit comments