mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 09:35:40 -05:00
select cluster page and status update for tool when installing (#4251)
This commit is contained in:
@@ -67,7 +67,8 @@ export interface ToolInfo {
|
||||
export enum ToolInstallationStatus {
|
||||
Installed,
|
||||
NotInstalled,
|
||||
Installing
|
||||
Installing,
|
||||
FailedToInstall
|
||||
}
|
||||
|
||||
export enum ClusterType {
|
||||
|
||||
@@ -102,9 +102,10 @@ export class CreateClusterModel implements Scriptable {
|
||||
return promise;
|
||||
}
|
||||
|
||||
public installTools(): Thenable<void> {
|
||||
public installTool(tool: ToolInfo): Thenable<void> {
|
||||
let promise = new Promise<void>(resolve => {
|
||||
setTimeout(() => {
|
||||
tool.status = ToolInstallationStatus.Installed;
|
||||
this._tmp_tools_installed = true;
|
||||
resolve();
|
||||
}, 2000);
|
||||
|
||||
@@ -31,7 +31,7 @@ export class CreateClusterWizard extends WizardBase<CreateClusterModel, CreateCl
|
||||
let selectTargetClusterPage = new SelectExistingClusterPage(this);
|
||||
let summaryPage = new SummaryPage(this);
|
||||
let targetClusterTypePage = new SelectTargetClusterTypePage(this);
|
||||
this.setPages([targetClusterTypePage, settingsPage, clusterProfilePage, selectTargetClusterPage, summaryPage]);
|
||||
this.setPages([targetClusterTypePage, selectTargetClusterPage, clusterProfilePage, settingsPage, summaryPage]);
|
||||
|
||||
this.wizardObject.generateScriptButton.label = localize('bdc-create.generateScriptsButtonText', 'Generate Scripts');
|
||||
this.wizardObject.generateScriptButton.hidden = false;
|
||||
|
||||
@@ -19,6 +19,12 @@ export class ClusterProfilePage extends WizardPageBase<CreateClusterWizard> {
|
||||
wizard);
|
||||
}
|
||||
|
||||
public onEnter() {
|
||||
this.wizard.wizardObject.registerNavigationValidator(() => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
protected initialize(view: sqlops.ModelView): Thenable<void> {
|
||||
let formBuilder = view.modelBuilder.formContainer();
|
||||
let form = formBuilder.component();
|
||||
|
||||
@@ -9,61 +9,31 @@ import * as vscode from 'vscode';
|
||||
import * as os from 'os';
|
||||
import { WizardPageBase } from '../../wizardPageBase';
|
||||
import { CreateClusterWizard } from '../createClusterWizard';
|
||||
import { TargetClusterType } from '../../../interfaces';
|
||||
import { setActiveKubeconfig } from '../../../config/config';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
const ClusterTypeRadioButtonGroupName = 'SelectClusterType';
|
||||
const ClusterRadioButtonGroupName = 'cluster';
|
||||
|
||||
export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizard> {
|
||||
constructor(wizard: CreateClusterWizard) {
|
||||
super(localize('bdc-create.selectTargetClusterPageTitle', 'Where do you want to deploy this SQL Server big data cluster?'),
|
||||
localize('bdc-create.selectTargetClusterPageDescription', 'Select an existing Kubernetes cluster or choose a cluster type you want to deploy'),
|
||||
wizard);
|
||||
}
|
||||
|
||||
private existingClusterOption: sqlops.RadioButtonComponent;
|
||||
private createAksClusterOption: sqlops.RadioButtonComponent;
|
||||
private pageContainer: sqlops.DivContainer;
|
||||
private existingClusterControl: sqlops.FlexContainer;
|
||||
private createAksClusterControl: sqlops.FlexContainer;
|
||||
private clusterContextsLabel: sqlops.TextComponent;
|
||||
private errorLoadingClustersLabel: sqlops.TextComponent;
|
||||
private clusterContextContainer: sqlops.DivContainer;
|
||||
|
||||
private cards: sqlops.CardComponent[];
|
||||
constructor(wizard: CreateClusterWizard) {
|
||||
super(localize('bdc-create.selectTargetClusterPageTitle', 'Where do you want to deploy this SQL Server big data cluster?'),
|
||||
localize('bdc-create.selectTargetClusterPageDescription', 'Select the kubeconfig file and then select a cluster context from the list'),
|
||||
wizard);
|
||||
}
|
||||
|
||||
protected initialize(view: sqlops.ModelView): Thenable<void> {
|
||||
let self = this;
|
||||
this.wizard.model.targetClusterType = TargetClusterType.ExistingKubernetesCluster;
|
||||
this.existingClusterOption = this.createTargetTypeRadioButton(view, localize('bdc-create.existingK8sCluster', 'Existing Kubernetes cluster'), true);
|
||||
this.createAksClusterOption = this.createTargetTypeRadioButton(view, localize('bdc-create.createAksCluster', 'Create new Azure Kubernetes Service cluster'));
|
||||
|
||||
this.existingClusterOption.onDidClick(() => {
|
||||
self.pageContainer.clearItems();
|
||||
self.pageContainer.addItem(self.existingClusterControl);
|
||||
self.wizard.model.targetClusterType = TargetClusterType.ExistingKubernetesCluster;
|
||||
});
|
||||
|
||||
this.createAksClusterOption.onDidClick(() => {
|
||||
self.pageContainer.clearItems();
|
||||
self.pageContainer.addItem(self.createAksClusterControl);
|
||||
self.wizard.model.targetClusterType = TargetClusterType.NewAksCluster;
|
||||
});
|
||||
|
||||
let optionGroup = view.modelBuilder.divContainer().withItems([this.existingClusterOption, this.createAksClusterOption],
|
||||
{ CSSStyles: { 'margin-right': '30px' } }).withLayout({ width: 'auto' }).component();
|
||||
this.initExistingClusterControl(view);
|
||||
this.initAksClusterControl(view);
|
||||
this.pageContainer = view.modelBuilder.divContainer().withItems([this.existingClusterControl]).withLayout({ width: '100%' }).component();
|
||||
let container = view.modelBuilder.flexContainer().withItems([optionGroup, this.pageContainer], { flex: '0 0 auto' }).withLayout({ flexFlow: 'row', alignItems: 'left' }).component();
|
||||
|
||||
let formBuilder = view.modelBuilder.formContainer().withFormItems(
|
||||
[
|
||||
{
|
||||
component: container,
|
||||
component: this.existingClusterControl,
|
||||
title: ''
|
||||
}
|
||||
],
|
||||
@@ -76,15 +46,28 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
return view.initializeModel(form);
|
||||
}
|
||||
|
||||
private createTargetTypeRadioButton(view: sqlops.ModelView, label: string, checked: boolean = false): sqlops.RadioButtonComponent {
|
||||
return view.modelBuilder.radioButton().withProperties({ label: label, name: ClusterTypeRadioButtonGroupName, checked: checked }).component();
|
||||
public onEnter() {
|
||||
this.wizard.wizardObject.registerNavigationValidator((e) => {
|
||||
if (e.lastPage > e.newPage) {
|
||||
this.wizard.wizardObject.message = null;
|
||||
return true;
|
||||
}
|
||||
let clusterSelected = this.wizard.model.selectedCluster !== undefined;
|
||||
if (!clusterSelected) {
|
||||
this.wizard.wizardObject.message = {
|
||||
text: localize('bdc-create.ClusterContextNotSelectedMessage', 'Please select a cluster context.'),
|
||||
level: sqlops.window.MessageLevel.Error
|
||||
};
|
||||
}
|
||||
return clusterSelected;
|
||||
});
|
||||
}
|
||||
|
||||
private initExistingClusterControl(view: sqlops.ModelView): void {
|
||||
let self = this;
|
||||
let sectionDescription = view.modelBuilder.text().withProperties({ value: localize('bdc-create.existingClusterSectionDescription', 'Select the cluster context you want to install the SQL Server big data cluster') }).component();
|
||||
let configFileLabel = view.modelBuilder.text().withProperties({ value: localize('bdc-create.kubeConfigFileLabelText', 'KubeConfig File') }).component();
|
||||
let configFileLabel = view.modelBuilder.text().withProperties({ value: localize('bdc-create.kubeConfigFileLabelText', 'Kube config file path') }).component();
|
||||
let configFileInput = view.modelBuilder.inputBox().withProperties({ width: '300px' }).component();
|
||||
configFileInput.enabled = false;
|
||||
let browseFileButton = view.modelBuilder.button().withProperties({ label: localize('bdc-browseText', 'Browse'), width: '100px' }).component();
|
||||
let configFileContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'row', alignItems: 'baseline' })
|
||||
@@ -92,7 +75,7 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
this.clusterContextsLabel = view.modelBuilder.text().withProperties({ value: localize('bdc-clusterContextsLabelText', 'Cluster Contexts') }).component();
|
||||
this.errorLoadingClustersLabel = view.modelBuilder.text().withProperties({ value: localize('bdc-errorLoadingClustersText', 'No cluster information is found in the config file or an error ocurred while loading the config file') }).component();
|
||||
this.clusterContextContainer = view.modelBuilder.divContainer().component();
|
||||
this.existingClusterControl = view.modelBuilder.divContainer().withItems([sectionDescription, configFileContainer, this.clusterContextContainer], { CSSStyles: { 'margin-top': '0px' } }).component();
|
||||
this.existingClusterControl = view.modelBuilder.divContainer().withItems([configFileContainer, this.clusterContextContainer], { CSSStyles: { 'margin-top': '0px' } }).component();
|
||||
|
||||
browseFileButton.onDidClick(async () => {
|
||||
let fileUris = await vscode.window.showOpenDialog(
|
||||
@@ -119,45 +102,31 @@ export class SelectExistingClusterPage extends WizardPageBase<CreateClusterWizar
|
||||
await setActiveKubeconfig(fileUri.fsPath);
|
||||
|
||||
let clusters = await self.wizard.model.loadClusters();
|
||||
|
||||
self.cards = [];
|
||||
if (clusters.length !== 0) {
|
||||
self.wizard.model.selectedCluster = clusters[0];
|
||||
for (let i = 0; i < clusters.length; i++) {
|
||||
let cluster = clusters[i];
|
||||
let card = view.modelBuilder.card().withProperties({
|
||||
selected: i === 0,
|
||||
label: cluster.clusterName,
|
||||
descriptions: [cluster.clusterName, cluster.userName],
|
||||
cardType: sqlops.CardType.ListItem,
|
||||
iconPath: {
|
||||
dark: self.wizard.context.asAbsolutePath('images/cluster_inverse.svg'),
|
||||
light: self.wizard.context.asAbsolutePath('images/cluster.svg')
|
||||
},
|
||||
let options = clusters.map(cluster => {
|
||||
let option = view.modelBuilder.radioButton().withProperties<sqlops.RadioButtonProperties>({
|
||||
label: cluster.contextName,
|
||||
checked: cluster.active,
|
||||
name: ClusterRadioButtonGroupName
|
||||
}).component();
|
||||
card.onCardSelectedChanged(() => {
|
||||
if (card.selected) {
|
||||
self.cards.forEach(c => {
|
||||
if (c !== card) {
|
||||
c.selected = false;
|
||||
}
|
||||
});
|
||||
self.wizard.model.selectedCluster = cluster;
|
||||
}
|
||||
|
||||
if (cluster.active) {
|
||||
self.wizard.model.selectedCluster = cluster;
|
||||
self.wizard.wizardObject.message = null;
|
||||
}
|
||||
|
||||
option.onDidClick(() => {
|
||||
self.wizard.model.selectedCluster = cluster;
|
||||
self.wizard.wizardObject.message = null;
|
||||
});
|
||||
self.cards.push(card);
|
||||
}
|
||||
return option;
|
||||
});
|
||||
|
||||
self.clusterContextContainer.addItem(self.clusterContextsLabel);
|
||||
self.clusterContextContainer.addItems(self.cards);
|
||||
self.clusterContextContainer.addItems(options);
|
||||
} else {
|
||||
self.clusterContextContainer.addItem(this.errorLoadingClustersLabel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initAksClusterControl(view: sqlops.ModelView): void {
|
||||
let placeholder = view.modelBuilder.text().withProperties({ value: 'AKS cluster place holder' }).component();
|
||||
this.createAksClusterControl = view.modelBuilder.divContainer().withItems([placeholder]).component();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { WizardPageBase } from '../../wizardPageBase';
|
||||
import { TargetClusterTypeInfo, ToolInstallationStatus } from '../../../interfaces';
|
||||
import { TargetClusterTypeInfo, ToolInstallationStatus, ToolInfo } from '../../../interfaces';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { CreateClusterWizard } from '../createClusterWizard';
|
||||
|
||||
@@ -25,6 +25,7 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
private refreshToolsButton: sqlops.window.Button;
|
||||
private isValid: boolean = false;
|
||||
private isLoading: boolean = false;
|
||||
private requiredTools: ToolInfo[];
|
||||
|
||||
constructor(wizard: CreateClusterWizard) {
|
||||
super(localize('bdc-create.selectTargetClusterTypePageTitle', 'Where do you want to deploy this SQL Server big data cluster?'),
|
||||
@@ -32,16 +33,24 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
wizard);
|
||||
this.installToolsButton = sqlops.window.createButton(InstallToolsButtonText);
|
||||
this.installToolsButton.hidden = true;
|
||||
this.installToolsButton.onClick(() => {
|
||||
this.toolsLoadingWrapper.loading = true;
|
||||
this.installToolsButton.onClick(async () => {
|
||||
this.wizard.wizardObject.message = null;
|
||||
this.installToolsButton.label = InstallingButtonText;
|
||||
this.installToolsButton.enabled = false;
|
||||
this.wizard.model.installTools().then(() => {
|
||||
this.installToolsButton.label = InstallToolsButtonText;
|
||||
this.installToolsButton.enabled = true;
|
||||
return this.updateRequiredToolStatus();
|
||||
});
|
||||
this.refreshToolsButton.enabled = false;
|
||||
if (this.requiredTools) {
|
||||
for (let i = 0; i < this.requiredTools.length; i++) {
|
||||
let tool = this.requiredTools[i];
|
||||
if (tool.status === ToolInstallationStatus.NotInstalled) {
|
||||
tool.status = ToolInstallationStatus.Installing;
|
||||
this.updateToolStatusTable();
|
||||
await this.wizard.model.installTool(tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.installToolsButton.label = InstallToolsButtonText;
|
||||
this.updateRequiredToolStatus();
|
||||
});
|
||||
this.wizard.addButton(this.installToolsButton);
|
||||
|
||||
@@ -51,31 +60,11 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
this.updateRequiredToolStatus();
|
||||
});
|
||||
this.wizard.addButton(this.refreshToolsButton);
|
||||
this.wizard.wizardObject.registerNavigationValidator(() => {
|
||||
if (this.isLoading) {
|
||||
let messageText = localize('bdc-create.ToolsRefreshingText', 'Please wait while the required tools status is being refreshed.');
|
||||
let messageLevel = sqlops.window.MessageLevel.Information;
|
||||
this.wizard.wizardObject.message = {
|
||||
level: messageLevel,
|
||||
text: messageText
|
||||
};
|
||||
return false;
|
||||
}
|
||||
if (!this.isValid) {
|
||||
let messageText = this.cards.filter(c => { return c.selected; }).length === 0 ?
|
||||
localize('bdc-create.TargetClusterTypeNotSelectedText', 'Please select a target cluster type') :
|
||||
localize('bdc-create.MissingToolsText', 'Please install the missing tools');
|
||||
this.wizard.wizardObject.message = {
|
||||
level: sqlops.window.MessageLevel.Error,
|
||||
text: messageText
|
||||
};
|
||||
}
|
||||
return this.isValid;
|
||||
});
|
||||
}
|
||||
|
||||
protected initialize(view: sqlops.ModelView): Thenable<void> {
|
||||
let self = this;
|
||||
self.registerNavigationValidator();
|
||||
return self.wizard.model.getAllTargetClusterTypeInfo().then((clusterTypes) => {
|
||||
self.cards = [];
|
||||
|
||||
@@ -129,6 +118,31 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
this.refreshToolsButton.hidden = false;
|
||||
this.refreshToolsButton.enabled = true;
|
||||
this.installToolsButton.enabled = false;
|
||||
this.registerNavigationValidator();
|
||||
}
|
||||
|
||||
private registerNavigationValidator(): void {
|
||||
this.wizard.wizardObject.registerNavigationValidator(() => {
|
||||
if (this.isLoading) {
|
||||
let messageText = localize('bdc-create.ToolsRefreshingText', 'Please wait while the required tools status is being refreshed.');
|
||||
let messageLevel = sqlops.window.MessageLevel.Information;
|
||||
this.wizard.wizardObject.message = {
|
||||
level: messageLevel,
|
||||
text: messageText
|
||||
};
|
||||
return false;
|
||||
}
|
||||
if (!this.isValid) {
|
||||
let messageText = this.cards.filter(c => { return c.selected; }).length === 0 ?
|
||||
localize('bdc-create.TargetClusterTypeNotSelectedText', 'Please select a target cluster type.') :
|
||||
localize('bdc-create.MissingToolsText', 'Please install the required tools.');
|
||||
this.wizard.wizardObject.message = {
|
||||
level: sqlops.window.MessageLevel.Error,
|
||||
text: messageText
|
||||
};
|
||||
}
|
||||
return this.isValid;
|
||||
});
|
||||
}
|
||||
|
||||
public onLeave(): void {
|
||||
@@ -136,7 +150,6 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
this.refreshToolsButton.hidden = true;
|
||||
}
|
||||
|
||||
|
||||
private createCard(view: sqlops.ModelView, targetClusterTypeInfo: TargetClusterTypeInfo): sqlops.CardComponent {
|
||||
let self = this;
|
||||
let card = view.modelBuilder.card().withProperties<sqlops.CardProperties>({
|
||||
@@ -165,7 +178,7 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
}
|
||||
self.updateRequiredToolStatus();
|
||||
} else {
|
||||
if (self.cards.filter(c => { return c !== card && c.selected }).length === 0) {
|
||||
if (self.cards.filter(c => { return c !== card && c.selected; }).length === 0) {
|
||||
card.selected = true;
|
||||
}
|
||||
}
|
||||
@@ -181,29 +194,38 @@ export class SelectTargetClusterTypePage extends WizardPageBase<CreateClusterWiz
|
||||
this.refreshToolsButton.enabled = false;
|
||||
this.installToolsButton.enabled = false;
|
||||
return this.wizard.model.getRequiredToolStatus().then(tools => {
|
||||
this.requiredTools = tools;
|
||||
this.isLoading = false;
|
||||
this.toolsLoadingWrapper.loading = false;
|
||||
this.refreshToolsButton.enabled = true;
|
||||
this.installToolsButton.enabled = tools.filter(tool => tool.status !== ToolInstallationStatus.Installed).length !== 0;
|
||||
this.isValid = !this.installToolsButton.enabled;
|
||||
this.wizard.wizardObject.message = null;
|
||||
let tableData = tools.map(tool => {
|
||||
return [tool.name, tool.description, this.getStatusText(tool.status)];
|
||||
});
|
||||
this.toolsTable.data = tableData;
|
||||
this.updateToolStatusTable();
|
||||
});
|
||||
}
|
||||
|
||||
private getStatusText(status: ToolInstallationStatus): string {
|
||||
switch (status) {
|
||||
case ToolInstallationStatus.Installed:
|
||||
return localize('bdc-create.InstalledText', 'Installed');
|
||||
return '✔️ ' + localize('bdc-create.InstalledText', 'Installed');
|
||||
case ToolInstallationStatus.NotInstalled:
|
||||
return localize('bdc-create.NotInstalledText', 'Not Installed');
|
||||
return '❌ ' + localize('bdc-create.NotInstalledText', 'Not Installed');
|
||||
case ToolInstallationStatus.Installing:
|
||||
return localize('bdc-create.InstallingText', 'Installing');
|
||||
return '⌛ ' + localize('bdc-create.InstallingText', 'Installing...');
|
||||
case ToolInstallationStatus.FailedToInstall:
|
||||
return '❌ ' + localize('bdc-create.FailedToInstallText', 'Install Failed');
|
||||
default:
|
||||
return 'unknown status';
|
||||
}
|
||||
}
|
||||
|
||||
private updateToolStatusTable(): void {
|
||||
if (this.requiredTools) {
|
||||
let tableData = this.requiredTools.map(tool => {
|
||||
return [tool.name, tool.description, this.getStatusText(tool.status)];
|
||||
});
|
||||
this.toolsTable.data = tableData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,12 @@ export class SummaryPage extends WizardPageBase<CreateClusterWizard> {
|
||||
let form = formBuilder.component();
|
||||
return view.initializeModel(form);
|
||||
}
|
||||
|
||||
public onEnter(): void {
|
||||
this.wizard.wizardObject.generateScriptButton.hidden = false;
|
||||
}
|
||||
|
||||
public onLeave(): void {
|
||||
this.wizard.wizardObject.generateScriptButton.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user