/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; import { ResourceTypeService } from './resourceTypeService'; import * as loc from '../localizedConstants'; interface IGalleryExtension { name: string; version: string; date: string; displayName: string; publisherId: string; publisher: string; publisherDisplayName: string; description: string; preview: boolean; } export class UriHandlerService implements vscode.UriHandler { constructor(private _resourceTypeService: ResourceTypeService) { } async handleUri(uri: vscode.Uri): Promise { // Path to start a deployment // Supported URI parameters : // - type (optional) : The resource type to start the deployment for // - extension (optional) : The ID of the extension that is required to start the deployment // - params (optional) : A JSON blob of variable names/values to pass as initial values to the wizard. Note // that the JSON blob must be URI-encoded in order to be properly handled // Example URIs : // azuredatastudio://Microsoft.resource-deployment/deploy // azuredatastudio://Microsoft.resource-deployment/deploy?type=arc-controller // azuredatastudio://Microsoft.resource-deployment/deploy?type=arc-controller&extension=Microsoft.arc // azuredatastudio://Microsoft.resource-deployment/deploy?type=arc-controller¶ms=%7B%22AZDATA_NB_VAR_ARC_SUBSCRIPTION%22%3A%22abdcef12-3456-7890-abcd-ef1234567890%22%2C%22AZDATA_NB_VAR_ARC_RESOURCE_GROUP%22%3A%22my-rg%22%2C%22AZDATA_NB_VAR_ARC_DATA_CONTROLLER_LOCATION%22%3A%22westus%22%2C%22AZDATA_NB_VAR_ARC_DATA_CONTROLLER_NAME%22%3A%22arc-dc%22%7D if (uri.path === '/deploy') { const params = uri.query.split('&').map(kv => kv.split('=')); const paramType = params.find(param => param[0] === 'type')?.[1]; const extensionId = params.find(param => param[0] === 'extension')?.[1]; if (extensionId) { const installedExtension = vscode.extensions.getExtension(extensionId); if (!installedExtension) { // The required extension isn't installed, prompt user to install it const extensionGalleryInfo = await vscode.commands.executeCommand('workbench.extensions.getExtensionFromGallery', extensionId); if (extensionGalleryInfo) { const response = await vscode.window.showInformationMessage( loc.extensionRequiredPrompt(extensionGalleryInfo.displayName), loc.install); if (response === loc.install) { await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, title: loc.installingExtension(extensionGalleryInfo.displayName), cancellable: false }, async (_progress, _token) => { await vscode.commands.executeCommand('workbench.extensions.installExtension', extensionId); } ); } else { // If user didn't install extension we wouldn't expect the deployment to work so just return console.log(`User cancelled out of prompt to install required extension '${extensionId}' for Resource Deployment URI`); return; } } else { // If we can't find the extension in the gallery then we won't be able to install it - so just inform the user // that the ID is invalid and return since we wouldn't expect the deployment to work without the extension vscode.window.showErrorMessage(loc.unknownExtension(extensionId)); return; } } else { // Extension is already installed, ensure that it's activated before continuing on await installedExtension.activate(); } } const wizardParams = JSON.parse(params.find(param => param[0] === 'params')?.[1] ?? '{}'); const resourceType = this._resourceTypeService.getResourceTypes().find(type => type.name === paramType); if (paramType && !resourceType) { console.warn(`Unknown resource type ${paramType}`); } if (resourceType) { this._resourceTypeService.startDeployment(resourceType, undefined, wizardParams); } else { return vscode.commands.executeCommand('azdata.resource.deploy'); } } } }