dialog assisted notebooks (#6564)

This commit is contained in:
Alan Ren
2019-08-05 16:01:34 -07:00
committed by GitHub
parent 2431bb8e37
commit 2bb8806da6
13 changed files with 1074 additions and 225 deletions

View File

@@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import { DialogBase } from './dialogBase';
import { INotebookService } from '../services/notebookService';
import { DeploymentProvider, DialogFieldInfo, FieldType } from '../interfaces';
const localize = nls.loadMessageBundle();
export class DeploymentDialog extends DialogBase {
private variables: { [s: string]: string | undefined; } = {};
constructor(context: vscode.ExtensionContext,
private notebookService: INotebookService,
private deploymentProvider: DeploymentProvider) {
super(context, deploymentProvider.dialog.title, deploymentProvider.dialog.name, false);
this._dialogObject.okButton.label = localize('deploymentDialog.OKButtonText', 'Open Notebook');
this._dialogObject.okButton.onClick(() => this.onComplete());
}
protected initializeDialog() {
const tabs: azdata.window.DialogTab[] = [];
this.deploymentProvider.dialog.tabs.forEach(tabInfo => {
const tab = azdata.window.createTab(tabInfo.title);
tab.registerContent((view: azdata.ModelView) => {
const sections: azdata.FormComponentGroup[] = [];
tabInfo.sections.forEach(sectionInfo => {
const fields: azdata.FormComponent[] = [];
sectionInfo.fields.forEach(fieldInfo => {
this.addField(view, fields, fieldInfo);
});
sections.push({ title: sectionInfo.title, components: fields });
});
const formBuilder = view.modelBuilder.formContainer().withFormItems(
sections,
{
horizontal: false
}
);
const form = formBuilder.withLayout({ width: '100%' }).component();
return view.initializeModel(form);
});
tabs.push(tab);
});
this._dialogObject.content = tabs;
}
private addField(view: azdata.ModelView, fields: azdata.FormComponent[], fieldInfo: DialogFieldInfo): void {
switch (fieldInfo.type) {
case FieldType.Options:
this.addOptionsTypeField(view, fields, fieldInfo);
break;
case FieldType.DateTimeText:
case FieldType.Number:
case FieldType.Password:
case FieldType.Text:
this.addInputTypeField(view, fields, fieldInfo);
break;
}
}
private addOptionsTypeField(view: azdata.ModelView, fields: azdata.FormComponent[], fieldInfo: DialogFieldInfo): void {
const component = view.modelBuilder.dropDown().withProperties<azdata.DropDownProperties>({ values: fieldInfo.options, value: fieldInfo.defaultValue }).component();
this.variables[fieldInfo.variableName] = fieldInfo.defaultValue;
this._toDispose.push(component.onValueChanged(() => { this.variables[fieldInfo.variableName] = <string>component.value; }));
fields.push({ title: fieldInfo.label, component: component });
}
private addInputTypeField(view: azdata.ModelView, fields: azdata.FormComponent[], fieldInfo: DialogFieldInfo): void {
let inputType: azdata.InputBoxInputType = 'text';
let defaultValue: string | undefined = fieldInfo.defaultValue;
switch (fieldInfo.type) {
case FieldType.Number:
inputType = 'number';
break;
case FieldType.Password:
inputType = 'password';
break;
case FieldType.DateTimeText:
defaultValue = fieldInfo.defaultValue + new Date().toISOString().slice(0, 19).replace(/[^0-9]/g, '');
break;
}
const component = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({
value: defaultValue, ariaLabel: fieldInfo.label, inputType: inputType, min: fieldInfo.min, max: fieldInfo.max, required: fieldInfo.required, placeHolder: fieldInfo.placeHolder
}).component();
this.variables[fieldInfo.variableName] = defaultValue;
this._toDispose.push(component.onTextChanged(() => { this.variables[fieldInfo.variableName] = component.value; }));
fields.push({ title: fieldInfo.label, component: component });
if (fieldInfo.type === FieldType.Password && fieldInfo.confirmationRequired) {
const confirmPasswordComponent = view.modelBuilder.inputBox().withProperties<azdata.InputBoxProperties>({ ariaLabel: fieldInfo.confirmationLabel, inputType: inputType, required: true }).component();
fields.push({ title: fieldInfo.confirmationLabel, component: confirmPasswordComponent });
this._dialogObject.registerCloseValidator((): boolean => {
const passwordMatches = component.value === confirmPasswordComponent.value;
if (!passwordMatches) {
this._dialogObject.message = { level: azdata.window.MessageLevel.Error, text: localize('passwordNotMatch', "{0} doesn't match the confirmation password", fieldInfo.label) };
}
return passwordMatches;
});
const checkPassword = (): void => {
const passwordMatches = component.value === confirmPasswordComponent.value;
if (passwordMatches) {
this._dialogObject.message = { text: '' };
}
};
this._toDispose.push(component.onTextChanged(() => {
checkPassword();
}));
this._toDispose.push(confirmPasswordComponent.onTextChanged(() => {
checkPassword();
}));
}
}
private onComplete(): void {
Object.keys(this.variables).forEach(key => {
process.env[key] = this.variables[key];
});
this.notebookService.launchNotebook(this.deploymentProvider.notebook);
this.dispose();
}
}

View File

@@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
export abstract class DialogBase {
protected _toDispose: vscode.Disposable[] = [];
protected _dialogObject: azdata.window.Dialog;
constructor(protected extensionContext: vscode.ExtensionContext, dialogTitle: string, dialogName: string, isWide: boolean = false) {
this._dialogObject = azdata.window.createModelViewDialog(dialogTitle, dialogName, isWide);
this._dialogObject.cancelButton.onClick(() => this.onCancel());
}
protected abstract initializeDialog(): void;
public open(): void {
this.initializeDialog();
azdata.window.openDialog(this._dialogObject);
}
protected onCancel(): void {
this.dispose();
}
protected dispose(): void {
this._toDispose.forEach(disposable => disposable.dispose());
}
}

View File

@@ -11,13 +11,13 @@ import * as vscode from 'vscode';
import { ResourceType, DeploymentProvider } from '../interfaces';
import { IToolsService } from '../services/toolsService';
import { INotebookService } from '../services/notebookService';
import { DialogBase } from './dialogBase';
import { DeploymentDialog } from './deploymentDialog';
const localize = nls.loadMessageBundle();
export class ResourceDeploymentDialog {
export class ResourceTypePickerDialog extends DialogBase {
private _selectedResourceType: ResourceType;
private _toDispose: vscode.Disposable[] = [];
private _dialogObject: azdata.window.Dialog;
private _resourceTypeCards: azdata.CardComponent[] = [];
private _view!: azdata.ModelView;
private _resourceDescriptionLabel!: azdata.TextComponent;
@@ -26,19 +26,18 @@ export class ResourceDeploymentDialog {
private _cardResourceTypeMap: Map<string, azdata.CardComponent> = new Map();
private _optionDropDownMap: Map<string, azdata.DropDownComponent> = new Map();
constructor(private context: vscode.ExtensionContext,
constructor(context: vscode.ExtensionContext,
private notebookService: INotebookService,
private toolsService: IToolsService,
private resourceTypeService: IResourceTypeService,
resourceType: ResourceType) {
super(context, localize('resourceTypePickerDialog.title', "Select the deployment options"), 'ResourceTypePickerDialog', true);
this._selectedResourceType = resourceType;
this._dialogObject = azdata.window.createModelViewDialog(localize('deploymentDialog.title', 'Select the deployment options'), 'resourceDeploymentDialog', true);
this._dialogObject.cancelButton.onClick(() => this.onCancel());
this._dialogObject.okButton.label = localize('deploymentDialog.OKButtonText', 'Open Notebook');
this._dialogObject.okButton.label = localize('deploymentDialog.OKButtonText', 'Select');
this._dialogObject.okButton.onClick(() => this.onComplete());
}
private initializeDialog() {
initializeDialog() {
let tab = azdata.window.createTab('');
tab.registerContent((view: azdata.ModelView) => {
const tableWidth = 1126;
@@ -98,17 +97,12 @@ export class ResourceDeploymentDialog {
this._dialogObject.content = [tab];
}
public open(): void {
this.initializeDialog();
azdata.window.openDialog(this._dialogObject);
}
private addCard(resourceType: ResourceType): void {
const card = this._view.modelBuilder.card().withProperties<azdata.CardProperties>({
cardType: azdata.CardType.VerticalButton,
iconPath: {
dark: this.context.asAbsolutePath(resourceType.icon.dark),
light: this.context.asAbsolutePath(resourceType.icon.light)
dark: this.extensionContext.asAbsolutePath(resourceType.icon.dark),
light: this.extensionContext.asAbsolutePath(resourceType.icon.light)
},
label: resourceType.displayName,
selected: (this._selectedResourceType && this._selectedResourceType.name === resourceType.name)
@@ -180,17 +174,14 @@ export class ResourceDeploymentDialog {
return this._selectedResourceType.getProvider(options)!;
}
private onCancel(): void {
this.dispose();
}
private onComplete(): void {
const provider = this.getCurrentProvider();
this.notebookService.launchNotebook(provider.notebook);
if (provider.dialog) {
const dialog = new DeploymentDialog(this.extensionContext, this.notebookService, provider);
dialog.open();
} else {
this.notebookService.launchNotebook(provider.notebook);
}
this.dispose();
}
private dispose(): void {
this._toDispose.forEach(disposable => disposable.dispose());
}
}