Alanren/tool check (#5810)

* tool check

* tools table update

* buttons

* update tools table

* remove tool status check

* updates

* PR comments
This commit is contained in:
Alan Ren
2019-06-03 14:32:10 -07:00
committed by GitHub
parent 639bd5a550
commit aaa2ef3a97
13 changed files with 50 additions and 289 deletions

View File

@@ -1,29 +0,0 @@
{
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python",
"version": "3.6.6",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [
{
"cell_type": "markdown",
"source": "TODO",
"metadata": {}
}
]
}

View File

@@ -1,29 +0,0 @@
{
"metadata": {
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python",
"version": "3.6.6",
"mimetype": "text/x-python",
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"pygments_lexer": "ipython3",
"nbconvert_exporter": "python",
"file_extension": ".py"
}
},
"nbformat_minor": 2,
"nbformat": 4,
"cells": [
{
"cell_type": "markdown",
"source": "TODO",
"metadata": {}
}
]
}

View File

@@ -13,8 +13,7 @@
"azdata": "^1.6.0" "azdata": "^1.6.0"
}, },
"activationEvents": [ "activationEvents": [
"onCommand:azdata.resource.sql-image.deploy", "*"
"onCommand:azdata.resource.sql-bdc.deploy"
], ],
"main": "./out/main", "main": "./out/main",
"repository": { "repository": {
@@ -22,7 +21,8 @@
"url": "https://github.com/Microsoft/azuredatastudio.git" "url": "https://github.com/Microsoft/azuredatastudio.git"
}, },
"extensionDependencies": [ "extensionDependencies": [
"Microsoft.mssql" "microsoft.mssql",
"microsoft.notebook"
], ],
"contributes": { "contributes": {
"commands": [ "commands": [
@@ -35,6 +35,11 @@
"command": "azdata.resource.sql-bdc.deploy", "command": "azdata.resource.sql-bdc.deploy",
"title": "%deploy-sql-bdc-command-name%", "title": "%deploy-sql-bdc-command-name%",
"category": "%deploy-resource-command-category%" "category": "%deploy-resource-command-category%"
},
{
"command": "azdata.resource.deploy",
"title": "%deploy-resource-command-name%",
"category": "%deploy-resource-command-category%"
} }
], ],
"menus": { "menus": {
@@ -119,10 +124,6 @@
"name": "version", "name": "version",
"displayName": "%version-display-name%", "displayName": "%version-display-name%",
"values": [ "values": [
{
"name": "ctp2.5",
"displayName": "%sql-2019ctp25-display-name%"
},
{ {
"name": "ctp3.0", "name": "ctp3.0",
"displayName": "%sql-2019ctp30-display-name%" "displayName": "%sql-2019ctp30-display-name%"
@@ -145,33 +146,6 @@
} }
], ],
"providers": [ "providers": [
{
"notebook": "%bdc-ctp25-aks-notebook%",
"requiredTools": [
{
"name": "kubectl"
},
{
"name": "azcli"
},
{
"name": "mssqlctl"
}
],
"when": "target=aks&&version=ctp2.5"
},
{
"notebook": "%bdc-ctp25-existing-cluster-notebook%",
"requiredTools": [
{
"name": "kubectl"
},
{
"name": "mssqlctl"
}
],
"when": "target=existingCluster&&version=ctp2.5"
},
{ {
"notebook": "%bdc-ctp30-aks-notebook%", "notebook": "%bdc-ctp30-aks-notebook%",
"requiredTools": [ "requiredTools": [

View File

@@ -3,6 +3,7 @@
"extension-description": "Provides a notebook-based experience to deploy SQL Server and other Azure Data Services", "extension-description": "Provides a notebook-based experience to deploy SQL Server and other Azure Data Services",
"deploy-sql-image-command-name": "Deploy SQL Server on Docker…", "deploy-sql-image-command-name": "Deploy SQL Server on Docker…",
"deploy-sql-bdc-command-name": "Deploy SQL Server Big Data Cluster…", "deploy-sql-bdc-command-name": "Deploy SQL Server Big Data Cluster…",
"deploy-resource-command-name": "Deploy SQL Server…",
"deploy-resource-command-category": "Resource Deployment", "deploy-resource-command-category": "Resource Deployment",
"resource-type-sql-image-display-name": "Container Image", "resource-type-sql-image-display-name": "Container Image",
"resource-type-sql-image-description": "SQL Server container image on Docker", "resource-type-sql-image-description": "SQL Server container image on Docker",
@@ -13,13 +14,10 @@
"sql-2019-display-name": "SQL Server 2019", "sql-2019-display-name": "SQL Server 2019",
"sql-2017-docker-notebook": "./notebooks/sql2017-image-docker.ipynb", "sql-2017-docker-notebook": "./notebooks/sql2017-image-docker.ipynb",
"sql-2019-docker-notebook": "./notebooks/sql2019-image-docker.ipynb", "sql-2019-docker-notebook": "./notebooks/sql2019-image-docker.ipynb",
"sql-2019ctp25-display-name": "SQL Server 2019 Big Data Cluster CTP 2.5",
"sql-2019ctp30-display-name": "SQL Server 2019 Big Data Cluster CTP 3.0", "sql-2019ctp30-display-name": "SQL Server 2019 Big Data Cluster CTP 3.0",
"bdc-deployment-target": "Deployment target", "bdc-deployment-target": "Deployment target",
"bdc-deployment-target-aks": "New Azure Kubernetes Service Cluster", "bdc-deployment-target-aks": "New Azure Kubernetes Service Cluster",
"bdc-deployment-target-existing-cluster": "Existing Kubernetes Cluster", "bdc-deployment-target-existing-cluster": "Existing Kubernetes Cluster",
"bdc-ctp25-aks-notebook": "./notebooks/sql2019-ctp25-bdc-aks.ipynb",
"bdc-ctp25-existing-cluster-notebook": "./notebooks/sql2019-ctp25-bdc-existing-cluster.ipynb",
"bdc-ctp30-aks-notebook": "./notebooks/sql2019-ctp30-bdc-aks.ipynb", "bdc-ctp30-aks-notebook": "./notebooks/sql2019-ctp30-bdc-aks.ipynb",
"bdc-ctp30-existing-cluster-notebook": "./notebooks/sql2019-ctp30-bdc-existing-cluster.ipynb" "bdc-ctp30-existing-cluster-notebook": "./notebooks/sql2019-ctp30-bdc-existing-cluster.ipynb"
} }

View File

@@ -51,28 +51,9 @@ export enum ToolType {
MSSQLCtl MSSQLCtl
} }
export interface ToolStatusInfo {
type: ToolType;
name: string;
description: string;
version: string;
status: ToolInstallationStatus;
}
export interface ITool { export interface ITool {
readonly name: string; readonly name: string;
readonly displayName: string; readonly displayName: string;
readonly description: string; readonly description: string;
readonly type: ToolType; readonly type: ToolType;
readonly supportAutoInstall: boolean;
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus>;
install(version: string): Thenable<void>;
}
export enum ToolInstallationStatus {
NotInstalled,
Installed,
Installing,
FailedToInstall
} }

View File

@@ -28,14 +28,12 @@ export function activate(context: vscode.ExtensionContext) {
validationFailures.forEach(message => console.error(message)); validationFailures.forEach(message => console.error(message));
return; return;
} }
const openDialog = (resourceTypeName: string) => { const openDialog = (resourceTypeName: string) => {
const filtered = resourceTypes.filter(resourceType => resourceType.name === resourceTypeName); const filtered = resourceTypes.filter(resourceType => resourceType.name === resourceTypeName);
if (filtered.length !== 1) { if (filtered.length !== 1) {
vscode.window.showErrorMessage(localize('resourceDeployment.UnknownResourceType', 'The resource type: {0} is not defined', resourceTypeName)); vscode.window.showErrorMessage(localize('resourceDeployment.UnknownResourceType', 'The resource type: {0} is not defined', resourceTypeName));
} } else {
else { const dialog = new ResourceDeploymentDialog(context, notebookService, toolsService, resourceTypeService, filtered[0]);
let dialog = new ResourceDeploymentDialog(context, notebookService, toolsService, resourceTypeService, filtered[0]);
dialog.open(); dialog.open();
} }
}; };
@@ -46,6 +44,9 @@ export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('azdata.resource.sql-bdc.deploy', () => { vscode.commands.registerCommand('azdata.resource.sql-bdc.deploy', () => {
openDialog('sql-bdc'); openDialog('sql-bdc');
}); });
vscode.commands.registerCommand('azdata.resource.deploy', () => {
openDialog('sql-image');
});
} }
// this method is called when your extension is deactivated // this method is called when your extension is deactivated

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolType, ITool, ToolInstallationStatus } from '../../interfaces'; import { ToolType, ITool } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -23,21 +23,4 @@ export class AzCliTool implements ITool {
get displayName(): string { get displayName(): string {
return localize('resourceDeployment.AzCLIDisplayName', 'Azure CLI'); return localize('resourceDeployment.AzCLIDisplayName', 'Azure CLI');
} }
get supportAutoInstall(): boolean {
return true;
}
install(version: string): Thenable<void> {
throw new Error('Method not implemented.');
}
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus> {
let promise = new Promise<ToolInstallationStatus>(resolve => {
setTimeout(() => {
resolve(ToolInstallationStatus.Installed);
}, 500);
});
return promise;
}
} }

View File

@@ -3,11 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolType, ITool, ToolInstallationStatus } from '../../interfaces'; import { ToolType, ITool } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export class DockerTool implements ITool { export class DockerTool implements ITool {
get name(): string { get name(): string {
return 'docker'; return 'docker';
@@ -24,21 +23,4 @@ export class DockerTool implements ITool {
get displayName(): string { get displayName(): string {
return localize('resourceDeployment.DockerDisplayName', 'Docker'); return localize('resourceDeployment.DockerDisplayName', 'Docker');
} }
get supportAutoInstall(): boolean {
return true;
}
install(version: string): Thenable<void> {
throw new Error('Method not implemented.');
}
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus> {
let promise = new Promise<ToolInstallationStatus>(resolve => {
setTimeout(() => {
resolve(ToolInstallationStatus.Installed);
}, 500);
});
return promise;
}
} }

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolType, ITool, ToolInstallationStatus } from '../../interfaces'; import { ToolType, ITool } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -13,7 +13,7 @@ export class KubeCtlTool implements ITool {
} }
get description(): string { get description(): string {
return localize('resourceDeployment.KUBECTLDescription', 'Tool used for managing the Kubernetes cluster'); return localize('resourceDeployment.KubeCtlDescription', 'Tool used for managing the Kubernetes cluster');
} }
get type(): ToolType { get type(): ToolType {
@@ -21,23 +21,6 @@ export class KubeCtlTool implements ITool {
} }
get displayName(): string { get displayName(): string {
return localize('resourceDeployment.KUBECTLDisplayName', 'kubectl'); return localize('resourceDeployment.KubeCtlDisplayName', 'kubectl');
}
get supportAutoInstall(): boolean {
return true;
}
install(version: string): Thenable<void> {
throw new Error('Method not implemented.');
}
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus> {
let promise = new Promise<ToolInstallationStatus>(resolve => {
setTimeout(() => {
resolve(ToolInstallationStatus.Installed);
}, 500);
});
return promise;
} }
} }

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolType, ITool, ToolInstallationStatus } from '../../interfaces'; import { ToolType, ITool } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -13,7 +13,7 @@ export class MSSQLCtlTool implements ITool {
} }
get description(): string { get description(): string {
return localize('resourceDeployment.MSSQLCTLDescription', 'Command-line tool for installing and managing the SQL Server big data cluster'); return localize('resourceDeployment.MssqlCtlDescription', 'Command-line tool for installing and managing the SQL Server big data cluster');
} }
get type(): ToolType { get type(): ToolType {
@@ -21,32 +21,6 @@ export class MSSQLCtlTool implements ITool {
} }
get displayName(): string { get displayName(): string {
return localize('resourceDeployment.MSSQLCTLDisplayName', 'mssqlctl'); return localize('resourceDeployment.MssqlCtlDisplayName', 'mssqlctl');
}
isInstalled(versionExpression: string): Thenable<boolean> {
let promise = new Promise<boolean>(resolve => {
setTimeout(() => {
resolve(true);
}, 500);
});
return promise;
}
get supportAutoInstall(): boolean {
return true;
}
install(version: string): Thenable<void> {
throw new Error('Method not implemented.');
}
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus> {
let promise = new Promise<ToolInstallationStatus>(resolve => {
setTimeout(() => {
resolve(ToolInstallationStatus.Installed);
}, 500);
});
return promise;
} }
} }

View File

@@ -3,11 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolType, ITool, ToolInstallationStatus } from '../../interfaces'; import { ToolType, ITool } from '../../interfaces';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export class PythonTool implements ITool { export class PythonTool implements ITool {
get name(): string { get name(): string {
return 'python'; return 'python';
@@ -24,21 +23,4 @@ export class PythonTool implements ITool {
get displayName(): string { get displayName(): string {
return localize('resourceDeployment.PythonDisplayName', 'Python'); return localize('resourceDeployment.PythonDisplayName', 'Python');
} }
get supportAutoInstall(): boolean {
return true;
}
install(version: string): Thenable<void> {
throw new Error('Method not implemented.');
}
getInstallationStatus(versionExpression: string): Thenable<ToolInstallationStatus> {
let promise = new Promise<ToolInstallationStatus>(resolve => {
setTimeout(() => {
resolve(ToolInstallationStatus.Installed);
}, 500);
});
return promise;
}
} }

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict'; 'use strict';
import { ToolRequirementInfo, ToolStatusInfo, ITool } from '../interfaces'; import { ITool } from '../interfaces';
import { PythonTool } from './tools/pythonTool'; import { PythonTool } from './tools/pythonTool';
import { DockerTool } from './tools/dockerTool'; import { DockerTool } from './tools/dockerTool';
import { AzCliTool } from './tools/azCliTool'; import { AzCliTool } from './tools/azCliTool';
@@ -11,42 +11,17 @@ import { MSSQLCtlTool } from './tools/mssqlCtlTool';
import { KubeCtlTool } from './tools/kubeCtlTool'; import { KubeCtlTool } from './tools/kubeCtlTool';
export interface IToolsService { export interface IToolsService {
getToolStatus(toolRequirements: ToolRequirementInfo[]): Thenable<ToolStatusInfo[]>;
getToolByName(toolName: string): ITool | undefined; getToolByName(toolName: string): ITool | undefined;
} }
export class ToolsService implements IToolsService { export class ToolsService implements IToolsService {
private static readonly SupportedTools: ITool[] = [new PythonTool(), new DockerTool(), new AzCliTool(), new MSSQLCtlTool(), new KubeCtlTool()]; constructor() {
this.SupportedTools = [new PythonTool(), new DockerTool(), new AzCliTool(), new MSSQLCtlTool(), new KubeCtlTool()];
getToolStatus(toolRequirements: ToolRequirementInfo[]): Thenable<ToolStatusInfo[]> {
const toolStatusList: ToolStatusInfo[] = [];
let promises = [];
for (let i = 0; i < toolRequirements.length; i++) {
const toolRequirement = toolRequirements[i];
const tool = this.getToolByName(toolRequirement.name);
if (tool !== undefined) {
promises.push(tool.getInstallationStatus(toolRequirement.version).then(installStatus => {
toolStatusList.push(<ToolStatusInfo>{
name: tool.displayName,
description: tool.description,
status: installStatus,
version: toolRequirement.version
});
}));
}
}
return Promise.all(promises).then(() => { return toolStatusList; });
} }
private SupportedTools: ITool[];
getToolByName(toolName: string): ITool | undefined { getToolByName(toolName: string): ITool | undefined {
if (toolName) { return this.SupportedTools.find(t => t.name === toolName);
for (let i = 0; i < ToolsService.SupportedTools.length; i++) {
if (toolName === ToolsService.SupportedTools[i].name) {
return ToolsService.SupportedTools[i];
}
}
}
return undefined;
} }
} }

View File

@@ -8,7 +8,7 @@ import * as azdata from 'azdata';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { IResourceTypeService } from '../services/resourceTypeService'; import { IResourceTypeService } from '../services/resourceTypeService';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ResourceType, DeploymentProvider, ToolInstallationStatus } from '../interfaces'; import { ResourceType, DeploymentProvider } from '../interfaces';
import { IToolsService } from '../services/toolsService'; import { IToolsService } from '../services/toolsService';
import { INotebookService } from '../services/notebookService'; import { INotebookService } from '../services/notebookService';
@@ -41,6 +41,7 @@ export class ResourceDeploymentDialog {
private initializeDialog() { private initializeDialog() {
let tab = azdata.window.createTab(''); let tab = azdata.window.createTab('');
tab.registerContent((view: azdata.ModelView) => { tab.registerContent((view: azdata.ModelView) => {
const tableWidth = 1126;
this._view = view; this._view = view;
this.resourceTypeService.getResourceTypes().forEach(resourceType => this.addCard(resourceType)); this.resourceTypeService.getResourceTypes().forEach(resourceType => this.addCard(resourceType));
const cardsContainer = view.modelBuilder.flexContainer().withItems(this._resourceTypeCards, { flex: '0 0 auto', CSSStyles: { 'margin-bottom': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'left' }).component(); const cardsContainer = view.modelBuilder.flexContainer().withItems(this._resourceTypeCards, { flex: '0 0 auto', CSSStyles: { 'margin-bottom': '10px' } }).withLayout({ flexFlow: 'row', alignItems: 'left' }).component();
@@ -49,28 +50,22 @@ export class ResourceDeploymentDialog {
const toolColumn: azdata.TableColumn = { const toolColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolNameColumnHeader', 'Tool'), value: localize('deploymentDialog.toolNameColumnHeader', 'Tool'),
width: 100 width: 150
}; };
const descriptionColumn: azdata.TableColumn = { const descriptionColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolDescriptionColumnHeader', 'Description'), value: localize('deploymentDialog.toolDescriptionColumnHeader', 'Description'),
width: 500 width: 850
};
const versionColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolVersionColumnHeader', 'Version'),
width: 200
};
const statusColumn: azdata.TableColumn = {
value: localize('deploymentDialog.toolStatusColumnHeader', 'Status'),
width: 200
}; };
this._toolsTable = view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({ this._toolsTable = view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({
height: 150,
data: [], data: [],
columns: [toolColumn, descriptionColumn, versionColumn, statusColumn], columns: [toolColumn, descriptionColumn],
width: 1000 width: tableWidth
}).component(); }).component();
const toolsTableWrapper = view.modelBuilder.divContainer().withLayout({ width: tableWidth }).component();
toolsTableWrapper.addItem(this._toolsTable, { CSSStyles: { 'border-left': '1px solid silver', 'border-top': '1px solid silver' } });
const formBuilder = view.modelBuilder.formContainer().withFormItems( const formBuilder = view.modelBuilder.formContainer().withFormItems(
[ [
{ {
@@ -83,7 +78,7 @@ export class ResourceDeploymentDialog {
component: this._optionsContainer, component: this._optionsContainer,
title: localize('deploymentDialog.OptionsTitle', 'Options') title: localize('deploymentDialog.OptionsTitle', 'Options')
}, { }, {
component: this._toolsTable, component: toolsTableWrapper,
title: localize('deploymentDialog.RequiredToolsTitle', 'Required tools') title: localize('deploymentDialog.RequiredToolsTitle', 'Required tools')
} }
], ],
@@ -165,27 +160,18 @@ export class ResourceDeploymentDialog {
} }
private updateTools(): void { private updateTools(): void {
this.toolsService.getToolStatus(this.getCurrentProvider().requiredTools).then(toolStatus => { // do a 10 ms delay to workaround the issue of first time load:
let tableData = toolStatus.map(tool => { // during initialization this update to table will be processed prior to the table initialization update
return [tool.name, tool.description, tool.version, this.getToolStatusText(tool.status)]; // as a result the data will be overwritten, introduce a short delay so that the order of updates can be maintained.
setTimeout(() => {
const tools = this.getCurrentProvider().requiredTools;
const headerRowHeight = 28;
this._toolsTable.height = 25 * tools.length + headerRowHeight;
this._toolsTable.data = tools.map(toolRef => {
const tool = this.toolsService.getToolByName(toolRef.name)!;
return [tool.displayName, tool.description];
}); });
this._toolsTable.data = tableData; }, 10);
});
}
private getToolStatusText(status: ToolInstallationStatus): string {
switch (status) {
case ToolInstallationStatus.Installed:
return '✔️ ' + localize('deploymentDialog.InstalledText', 'Installed');
case ToolInstallationStatus.NotInstalled:
return '❌ ' + localize('deploymentDialog.NotInstalledText', 'Not Installed');
case ToolInstallationStatus.Installing:
return '⌛ ' + localize('deploymentDialog.InstallingText', 'Installing…');
case ToolInstallationStatus.FailedToInstall:
return '❌ ' + localize('deploymentDialog.FailedToInstallText', 'Install Failed');
default:
return 'unknown status';
}
} }
private getCurrentProvider(): DeploymentProvider { private getCurrentProvider(): DeploymentProvider {