GenerateToNotebook and Deploy buttons for Notebook Wizards (#12656)

* enable userChooses how to run notebook

* arc ext changes

* nb fixes

* working version

* revert unneeded changes

* fix comments

* Update interfaces.ts

* fix comments

* fix comments

* fix comments

* runAllCells instead of background execute

* pr feedback

* PR feedback

* pr feedback

* arc ext changes for new WizardInfo syntax

* fix doc comments

* pr feedback
This commit is contained in:
Arvind Ranasaria
2020-09-29 18:12:30 -07:00
committed by GitHub
parent fd5acf7ab1
commit b8de69dfac
15 changed files with 203 additions and 75 deletions

View File

@@ -56,7 +56,7 @@
{ {
"cell_type": "markdown", "cell_type": "markdown",
"source": [ "source": [
"### **Setup and Check Prerequisites**" "### **Setup**"
], ],
"metadata": { "metadata": {
"azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2" "azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2"

View File

@@ -144,9 +144,13 @@
"notebookWizard": { "notebookWizard": {
"notebook": "./notebooks/arcDeployment/deploy.arc.data.controller.ipynb", "notebook": "./notebooks/arcDeployment/deploy.arc.data.controller.ipynb",
"type": "new-arc-control-plane", "type": "new-arc-control-plane",
"runNotebook": false, "doneAction": {
"label": "%deploy.done.action%"
},
"scriptAction": {
"label": "%deploy.script.action%"
},
"codeCellInsertionPosition": 5, "codeCellInsertionPosition": 5,
"actionText": "%deploy.script.to.notebook.action%",
"title": "%arc.data.controller.new.wizard.title%", "title": "%arc.data.controller.new.wizard.title%",
"name": "arc.data.controller.new.wizard", "name": "arc.data.controller.new.wizard",
"labelPosition": "left", "labelPosition": "left",
@@ -521,9 +525,13 @@
{ {
"notebookWizard": { "notebookWizard": {
"notebook": "./notebooks/arcDeployment/deploy.sql.existing.arc.ipynb", "notebook": "./notebooks/arcDeployment/deploy.sql.existing.arc.ipynb",
"runNotebook": false, "doneAction": {
"label": "%deploy.done.action%"
},
"scriptAction": {
"label": "%deploy.script.action%"
},
"codeCellInsertionPosition": 5, "codeCellInsertionPosition": 5,
"actionText": "%deploy.script.to.notebook.action%",
"title": "%arc.sql.wizard.title%", "title": "%arc.sql.wizard.title%",
"name": "arc.sql.wizard", "name": "arc.sql.wizard",
"labelPosition": "left", "labelPosition": "left",
@@ -682,9 +690,13 @@
{ {
"notebookWizard": { "notebookWizard": {
"notebook": "./notebooks/arcDeployment/deploy.postgres.existing.arc.ipynb", "notebook": "./notebooks/arcDeployment/deploy.postgres.existing.arc.ipynb",
"runNotebook": false, "doneAction": {
"label": "%deploy.done.action%"
},
"scriptAction": {
"label": "%deploy.script.action%"
},
"codeCellInsertionPosition": 5, "codeCellInsertionPosition": 5,
"actionText": "%deploy.script.to.notebook.action%",
"title": "%arc.postgres.wizard.title%", "title": "%arc.postgres.wizard.title%",
"name": "arc.postgres.wizard", "name": "arc.postgres.wizard",
"labelPosition": "left", "labelPosition": "left",

View File

@@ -58,8 +58,8 @@
"arc.data.controller.summary.location": "Location", "arc.data.controller.summary.location": "Location",
"arc.data.controller.arc.data.controller.agreement": "I accept {0} and {1}.", "arc.data.controller.arc.data.controller.agreement": "I accept {0} and {1}.",
"microsoft.agreement.privacy.statement":"Microsoft Privacy Statement", "microsoft.agreement.privacy.statement":"Microsoft Privacy Statement",
"deploy.script.to.notebook.action":"Script to notebook", "deploy.script.action":"Script to notebook",
"deploy.done.action":"Deploy",
"resource.type.arc.sql.display.name": "Azure SQL managed instance - Azure Arc (preview)", "resource.type.arc.sql.display.name": "Azure SQL managed instance - Azure Arc (preview)",
"resource.type.arc.postgres.display.name": "PostgreSQL Hyperscale server groups - Azure Arc (preview)", "resource.type.arc.postgres.display.name": "PostgreSQL Hyperscale server groups - Azure Arc (preview)",

View File

@@ -114,21 +114,53 @@ export interface BdcWizardInfo {
notebook: string | NotebookPathInfo; notebook: string | NotebookPathInfo;
type: BdcDeploymentType; type: BdcDeploymentType;
} }
/**
* An object that configures Script and Done buttons of the wizard.
*/
export interface WizardAction {
label?: string
}
/**
* This object defines the shape, form and behavior of a Notebook Wizard.
*/
export interface NotebookWizardInfo extends WizardInfoBase { export interface NotebookWizardInfo extends WizardInfoBase {
/**
* path to the template python notebook that is modified with variables collected in the wizard. A copy of this modified notebook is executed at the end of the wizard either from commonadline of from notebook editor in ADS.
*/
notebook: string | NotebookPathInfo; notebook: string | NotebookPathInfo;
runNotebook?: boolean; /**
* 0 based position number where the variables values are inserted into the notebook as python statements.
*/
codeCellInsertionPosition?: number; codeCellInsertionPosition?: number;
/**
* This array defines the json for the pages of this wizard.
*/
pages: NotebookWizardPageInfo[] pages: NotebookWizardPageInfo[]
} }
export interface WizardInfoBase extends FieldInfoBase { export interface WizardInfoBase extends FieldInfoBase {
taskName?: string;
type?: DeploymentType; type?: DeploymentType;
actionText?: string; /**
* done button attributes.
*/
doneAction: WizardAction;
/**
* script button attributes.
*/
scriptAction?: WizardAction;
/**
* title displayed on every page of the wizard
*/
title: string; title: string;
name?: string; name?: string;
/**
* This array defines the json for the pages of this wizard.
*/
pages: PageInfoBase[]; pages: PageInfoBase[];
/**
* if true an auto generated summary page is inserted at the end of the wizard
*/
isSummaryPageAutoGenerated?: boolean isSummaryPageAutoGenerated?: boolean
} }
@@ -401,11 +433,7 @@ export const enum BdcDeploymentType {
ExistingOpenShift = 'existing-openshift' ExistingOpenShift = 'existing-openshift'
} }
export const enum ArcDeploymentType { export type DeploymentType = BdcDeploymentType;
NewControlPlane = 'new-control-plane'
}
export type DeploymentType = ArcDeploymentType | BdcDeploymentType;
export interface Command { export interface Command {
command: string; command: string;

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { FieldType, OptionsType } from './interfaces';
import { OptionsSourceType } from './helpers/optionSources'; import { OptionsSourceType } from './helpers/optionSources';
import { FieldType, OptionsType } from './interfaces';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -37,3 +37,5 @@ export const optionsTypeRadioOrDropdown = localize('optionsTypeRadioOrDropdown',
export const azdataEulaNotAccepted = localize('azdataEulaNotAccepted', "Deployment cannot continue. Azure Data CLI license terms have not yet been accepted. Please accept the EULA to enable the features that requires Azure Data CLI."); export const azdataEulaNotAccepted = localize('azdataEulaNotAccepted', "Deployment cannot continue. Azure Data CLI license terms have not yet been accepted. Please accept the EULA to enable the features that requires Azure Data CLI.");
export const azdataEulaDeclined = localize('azdataEulaDeclined', "Deployment cannot continue. Azure Data CLI license terms were declined.You can either Accept EULA to continue or Cancel this operation"); export const azdataEulaDeclined = localize('azdataEulaDeclined', "Deployment cannot continue. Azure Data CLI license terms were declined.You can either Accept EULA to continue or Cancel this operation");
export const acceptEulaAndSelect = localize('deploymentDialog.RecheckEulaButton', "Accept EULA & Select"); export const acceptEulaAndSelect = localize('deploymentDialog.RecheckEulaButton', "Accept EULA & Select");
export const scriptToNotebook = localize('ui.ScriptToNotebookButton', "Script");
export const deployNotebook = localize('ui.DeployButton', "Run");

View File

@@ -33,9 +33,9 @@ export interface NotebookExecutionResult {
} }
export interface INotebookService { export interface INotebookService {
launchNotebook(notebook: string | NotebookPathInfo): Promise<azdata.nb.NotebookEditor>; openNotebook(notebook: string | NotebookPathInfo): Promise<azdata.nb.NotebookEditor>;
launchNotebookWithEdits(notebook: string | NotebookPathInfo, cellStatements: string[], insertionPosition?: number): Promise<void>; openNotebookWithEdits(notebook: string | NotebookPathInfo, cellStatements: string[], insertionPosition?: number): Promise<azdata.nb.NotebookEditor>;
launchNotebookWithContent(title: string, content: string): Promise<azdata.nb.NotebookEditor>; openNotebookWithContent(title: string, content: string): Promise<azdata.nb.NotebookEditor>;
getNotebook(notebook: string | NotebookPathInfo): Promise<Notebook>; getNotebook(notebook: string | NotebookPathInfo): Promise<Notebook>;
getNotebookPath(notebook: string | NotebookPathInfo): string; getNotebookPath(notebook: string | NotebookPathInfo): string;
executeNotebook(notebook: any, env?: NodeJS.ProcessEnv): Promise<NotebookExecutionResult>; executeNotebook(notebook: any, env?: NodeJS.ProcessEnv): Promise<NotebookExecutionResult>;
@@ -47,38 +47,39 @@ export class NotebookService implements INotebookService {
constructor(private platformService: IPlatformService, private extensionPath: string) { } constructor(private platformService: IPlatformService, private extensionPath: string) { }
/** /**
* Launch notebook with file path * Open notebook with file path
* @param notebook the path of the notebook * @param notebook the path of the notebook
*/ */
async launchNotebook(notebook: string | NotebookPathInfo): Promise<azdata.nb.NotebookEditor> { async openNotebook(notebook: string | NotebookPathInfo): Promise<azdata.nb.NotebookEditor> {
const notebookPath = await this.getNotebookFullPath(notebook); const notebookPath = await this.getNotebookFullPath(notebook);
return await this.showNotebookAsUntitled(notebookPath); return await this.showNotebookAsUntitled(notebookPath);
} }
/** /**
* Inserts cell code given by {@param cellStatements} in an existing notebook given by {@param notebook} file path at the location * Inserts cell code given by {@param cellStatements} in an existing notebook given by {@param notebook} file path at the location
* {@param insertionPosition} and then launches the edited notebook. * {@param insertionPosition} and then opens the edited notebook.
* *
* @param notebook - the path to notebook that needs to be launched * @param notebook - the path to notebook that needs to be opened
* @param cellStatements - array of statements to be inserted in a cell * @param cellStatements - array of statements to be inserted in a cell
* @param insertionPosition - the position at which cells are inserted. Default is a new cell at the beginning of the notebook. * @param insertionPosition - the position at which cells are inserted. Default is a new cell at the beginning of the notebook.
*/ */
async launchNotebookWithEdits(notebook: string, cellStatements: string[], insertionPosition: number = 0): Promise<void> { async openNotebookWithEdits(notebook: string, cellStatements: string[], insertionPosition: number = 0): Promise<azdata.nb.NotebookEditor> {
const openedNotebook = await this.launchNotebook(notebook); const openedNotebook = await this.openNotebook(notebook);
await openedNotebook.edit((editBuilder: azdata.nb.NotebookEditorEdit) => { await openedNotebook.edit((editBuilder: azdata.nb.NotebookEditorEdit) => {
editBuilder.insertCell({ editBuilder.insertCell({
cell_type: 'code', cell_type: 'code',
source: cellStatements source: cellStatements
}, insertionPosition); }, insertionPosition);
}); });
return openedNotebook;
} }
/** /**
* Launch notebook with file path * Open notebook with given contents
* @param title the title of the notebook * @param title the title of the notebook
* @param content the notebook content * @param content the notebook content
*/ */
async launchNotebookWithContent(title: string, content: string): Promise<azdata.nb.NotebookEditor> { async openNotebookWithContent(title: string, content: string): Promise<azdata.nb.NotebookEditor> {
const uri: vscode.Uri = vscode.Uri.parse(`untitled:${this.findNextUntitledEditorName(title)}`); const uri: vscode.Uri = vscode.Uri.parse(`untitled:${this.findNextUntitledEditorName(title)}`);
return await azdata.nb.showNotebookDocument(uri, { return await azdata.nb.showNotebookDocument(uri, {
connectionProfile: undefined, connectionProfile: undefined,
@@ -150,11 +151,11 @@ export class NotebookService implements INotebookService {
platformService.logToOutputChannel(taskFailedMessage); platformService.logToOutputChannel(taskFailedMessage);
if (selectedOption === viewErrorDetail) { if (selectedOption === viewErrorDetail) {
try { try {
await this.launchNotebookWithContent(`${tempNotebookPrefix}-${getDateTimeString()}`, result.outputNotebook); await this.openNotebookWithContent(`${tempNotebookPrefix}-${getDateTimeString()}`, result.outputNotebook);
} catch (error) { } catch (error) {
const launchNotebookError = localize('resourceDeployment.FailedToOpenNotebook', "An error occurred launching the output notebook. {1}{2}.", EOL, getErrorMessage(error)); const openNotebookError = localize('resourceDeployment.FailedToOpenNotebook', "An error occurred opening the output notebook. {1}{2}.", EOL, getErrorMessage(error));
platformService.logToOutputChannel(launchNotebookError); platformService.logToOutputChannel(openNotebookError);
vscode.window.showErrorMessage(launchNotebookError); vscode.window.showErrorMessage(openNotebookError);
} }
} }
} else { } else {

View File

@@ -10,17 +10,17 @@ import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { DeploymentProvider, instanceOfAzureSQLVMDeploymentProvider, instanceOfCommandDeploymentProvider, instanceOfDialogDeploymentProvider, instanceOfDownloadDeploymentProvider, instanceOfNotebookBasedDialogInfo, instanceOfNotebookDeploymentProvider, instanceOfNotebookWizardDeploymentProvider, instanceOfWebPageDeploymentProvider, instanceOfWizardDeploymentProvider, NotebookInfo, NotebookPathInfo, ResourceType, ResourceTypeOption } from '../interfaces';
import { DeployAzureSQLVMWizard } from '../ui/deployAzureSQLVMWizard/deployAzureSQLVMWizard';
import { DeployClusterWizard } from '../ui/deployClusterWizard/deployClusterWizard';
import { DeploymentInputDialog } from '../ui/deploymentInputDialog';
import { NotebookWizard } from '../ui/notebookWizard/notebookWizard';
import { AzdataService } from './azdataService';
import { KubeService } from './kubeService';
import { INotebookService } from './notebookService'; import { INotebookService } from './notebookService';
import { IPlatformService } from './platformService'; import { IPlatformService } from './platformService';
import { IToolsService } from './toolsService'; import { IToolsService } from './toolsService';
import { ResourceType, ResourceTypeOption, NotebookPathInfo, DeploymentProvider, instanceOfWizardDeploymentProvider, instanceOfDialogDeploymentProvider, instanceOfNotebookDeploymentProvider, instanceOfDownloadDeploymentProvider, instanceOfWebPageDeploymentProvider, instanceOfCommandDeploymentProvider, instanceOfNotebookBasedDialogInfo, instanceOfNotebookWizardDeploymentProvider, NotebookInfo, instanceOfAzureSQLVMDeploymentProvider } from '../interfaces';
import { DeployClusterWizard } from '../ui/deployClusterWizard/deployClusterWizard';
import { DeploymentInputDialog } from '../ui/deploymentInputDialog';
import { KubeService } from './kubeService';
import { AzdataService } from './azdataService';
import { NotebookWizard } from '../ui/notebookWizard/notebookWizard';
import { DeployAzureSQLVMWizard } from '../ui/deployAzureSQLVMWizard/deployAzureSQLVMWizard';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export interface IResourceTypeService { export interface IResourceTypeService {
@@ -257,7 +257,7 @@ export class ResourceTypeService implements IResourceTypeService {
const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, this.toolsService, provider.dialog); const dialog = new DeploymentInputDialog(this.notebookService, this.platformService, this.toolsService, provider.dialog);
dialog.open(); dialog.open();
} else if (instanceOfNotebookDeploymentProvider(provider)) { } else if (instanceOfNotebookDeploymentProvider(provider)) {
this.notebookService.launchNotebook(provider.notebook); this.notebookService.openNotebook(provider.notebook);
} else if (instanceOfDownloadDeploymentProvider(provider)) { } else if (instanceOfDownloadDeploymentProvider(provider)) {
const taskName = localize('resourceDeployment.DownloadAndLaunchTaskName', "Download and launch installer, URL: {0}", provider.downloadUrl); const taskName = localize('resourceDeployment.DownloadAndLaunchTaskName', "Download and launch installer, URL: {0}", provider.downloadUrl);
azdata.tasks.startBackgroundOperation({ azdata.tasks.startBackgroundOperation({

View File

@@ -73,7 +73,7 @@ export class DeployAzureSQLVMWizard extends WizardBase<DeployAzureSQLVMWizard, W
const variableValueStatements = this.model.getCodeCellContentForNotebook(); const variableValueStatements = this.model.getCodeCellContentForNotebook();
const insertionPosition = 2; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook. const insertionPosition = 2; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook.
try { try {
await this.notebookService.launchNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition); await this.notebookService.openNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition);
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(error); vscode.window.showErrorMessage(error);
} }

View File

@@ -144,7 +144,7 @@ export class DeployClusterWizard extends WizardBase<DeployClusterWizard, WizardP
const variableValueStatements = this.model.getCodeCellContentForNotebook(this.toolsService.toolsForCurrentProvider); const variableValueStatements = this.model.getCodeCellContentForNotebook(this.toolsService.toolsForCurrentProvider);
const insertionPosition = 5; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook. const insertionPosition = 5; // Cell number 5 is the position where the python variable setting statements need to be inserted in this.wizardInfo.notebook.
try { try {
await this.notebookService.launchNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition); await this.notebookService.openNotebookWithEdits(this.wizardInfo.notebook, variableValueStatements, insertionPosition);
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(getErrorMessage(error)); vscode.window.showErrorMessage(getErrorMessage(error));
} }

View File

@@ -105,7 +105,7 @@ export class DeploymentInputDialog extends DialogBase {
const notebook = Array.isArray(this.dialogInfo.notebook) ? const notebook = Array.isArray(this.dialogInfo.notebook) ?
this.dialogInfo.notebook.find(nb => nb.type === model.getStringValue(NotebookTypeVariableName))?.path : this.dialogInfo.notebook.find(nb => nb.type === model.getStringValue(NotebookTypeVariableName))?.path :
this.dialogInfo.notebook; this.dialogInfo.notebook;
this.notebookService.launchNotebook(notebook!).catch(error => { this.notebookService.openNotebook(notebook!).catch(error => {
vscode.window.showErrorMessage(error); vscode.window.showErrorMessage(error);
}); });
} }

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.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as loc from '../../localizedConstants';
import { INotebookService, Notebook } from '../../services/notebookService'; import { INotebookService, Notebook } from '../../services/notebookService';
import { IToolsService } from '../../services/toolsService'; import { IToolsService } from '../../services/toolsService';
import { Model } from '../model'; import { Model } from '../model';
@@ -14,8 +14,6 @@ import { IPlatformService } from './../../services/platformService';
import { NotebookWizardAutoSummaryPage } from './notebookWizardAutoSummaryPage'; import { NotebookWizardAutoSummaryPage } from './notebookWizardAutoSummaryPage';
import { NotebookWizardPage } from './notebookWizardPage'; import { NotebookWizardPage } from './notebookWizardPage';
const localize = nls.loadMessageBundle();
export class NotebookWizard extends WizardBase<NotebookWizard, NotebookWizardPage, Model> { export class NotebookWizard extends WizardBase<NotebookWizard, NotebookWizardPage, Model> {
private _inputComponents: InputComponents = {}; private _inputComponents: InputComponents = {};
@@ -40,7 +38,8 @@ export class NotebookWizard extends WizardBase<NotebookWizard, NotebookWizardPag
if (this._wizardInfo.codeCellInsertionPosition === undefined) { if (this._wizardInfo.codeCellInsertionPosition === undefined) {
this._wizardInfo.codeCellInsertionPosition = 0; this._wizardInfo.codeCellInsertionPosition = 0;
} }
this.wizardObject.doneButton.label = _wizardInfo.actionText || this.wizardObject.doneButton.label; this.wizardObject.doneButton.label = _wizardInfo.doneAction?.label || loc.deployNotebook;
this.wizardObject.generateScriptButton.label = _wizardInfo.scriptAction?.label || loc.scriptToNotebook;
} }
public get deploymentType(): DeploymentType | undefined { public get deploymentType(): DeploymentType | undefined {
@@ -49,17 +48,37 @@ export class NotebookWizard extends WizardBase<NotebookWizard, NotebookWizardPag
protected initialize(): void { protected initialize(): void {
this.setPages(this.getPages()); this.setPages(this.getPages());
this.wizardObject.generateScriptButton.hidden = true;
this.wizardInfo.actionText = this.wizardInfo.actionText || localize('notebookWizard.ScriptToNotebook', "Script to Notebook");
this.wizardObject.doneButton.label = this.wizardInfo.actionText;
} }
protected onCancel(): void { protected onCancel(): void {
} }
protected async onGenerateScript(): Promise<void> {
try {
const notebook = await this.prepareNotebookAndEnvironment();
await this.openNotebook(notebook);
} catch (error) {
vscode.window.showErrorMessage(error);
}
}
protected async onOk(): Promise<void> { protected async onOk(): Promise<void> {
try {
const notebook = await this.prepareNotebookAndEnvironment();
const openedNotebook = await this.openNotebook(notebook);
openedNotebook.runAllCells();
} catch (error) {
vscode.window.showErrorMessage(error);
}
}
private async openNotebook(notebook: Notebook) {
const notebookPath = this.notebookService.getNotebookPath(this.wizardInfo.notebook);
return await this.notebookService.openNotebookWithContent(notebookPath, JSON.stringify(notebook, undefined, 4));
}
private async prepareNotebookAndEnvironment() {
await setModelValues(this.inputComponents, this.model); await setModelValues(this.inputComponents, this.model);
const env: NodeJS.ProcessEnv = {}; const env: NodeJS.ProcessEnv = process.env;
this.model.setEnvironmentVariables(env, (varName) => { this.model.setEnvironmentVariables(env, (varName) => {
const isPassword = !!this.inputComponents[varName]?.isPassword; const isPassword = !!this.inputComponents[varName]?.isPassword;
return isPassword; return isPassword;
@@ -85,17 +104,7 @@ export class NotebookWizard extends WizardBase<NotebookWizard, NotebookWizardPag
execution_count: 0 execution_count: 0
} }
); );
try { return notebook;
if (this.wizardInfo.runNotebook) {
this.notebookService.backgroundExecuteNotebook(this.wizardInfo.taskName, notebook, 'deploy', this.platformService, env);
} else {
Object.assign(process.env, env);
const notebookPath = this.notebookService.getNotebookPath(this.wizardInfo.notebook);
await this.notebookService.launchNotebookWithContent(notebookPath, JSON.stringify(notebook, undefined, 4));
}
} catch (error) {
vscode.window.showErrorMessage(error);
}
} }
private getPages(): NotebookWizardPage[] { private getPages(): NotebookWizardPage[] {

View File

@@ -9,6 +9,7 @@ import * as nls from 'vscode-nls';
import { NotebookWizardPageInfo } from '../../interfaces'; import { NotebookWizardPageInfo } from '../../interfaces';
import { initializeWizardPage, InputComponentInfo, setModelValues, Validator } from '../modelViewUtils'; import { initializeWizardPage, InputComponentInfo, setModelValues, Validator } from '../modelViewUtils';
import { WizardPageBase } from '../wizardPageBase'; import { WizardPageBase } from '../wizardPageBase';
import { WizardPageInfo } from '../wizardPageInfo';
import { NotebookWizard } from './notebookWizard'; import { NotebookWizard } from './notebookWizard';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -32,6 +33,20 @@ export class NotebookWizardPage extends WizardPageBase<NotebookWizard> {
); );
} }
/**
* If the return value is true then done button should be visible to the user
*/
private get isDoneButtonVisible(): boolean {
return !!this.wizard.wizardInfo.doneAction;
}
/**
* If the return value is true then generateScript button should be visible to the user
*/
private get isGenerateScriptButtonVisible(): boolean {
return !!this.wizard.wizardInfo.scriptAction;
}
public initialize(): void { public initialize(): void {
initializeWizardPage({ initializeWizardPage({
container: this.wizard.wizardObject, container: this.wizard.wizardObject,
@@ -64,7 +79,17 @@ export class NotebookWizardPage extends WizardPageBase<NotebookWizard> {
}); });
} }
public async onEnter(): Promise<void> { public async onEnter(pageInfo: WizardPageInfo): Promise<void> {
if (pageInfo.isLastPage) {
// on the last page either one or both of done button and generateScript button are visible depending on configuration of 'runNotebook' in wizard info
this.wizard.wizardObject.doneButton.hidden = !this.isDoneButtonVisible;
this.wizard.wizardObject.generateScriptButton.hidden = !this.isGenerateScriptButtonVisible;
} else {
//on any page but the last page doneButton and generateScriptButton are hidden
this.wizard.wizardObject.doneButton.hidden = true;
this.wizard.wizardObject.generateScriptButton.hidden = true;
}
if (this.pageInfo.isSummaryPage) { if (this.pageInfo.isSummaryPage) {
await setModelValues(this.wizard.inputComponents, this.wizard.model); await setModelValues(this.wizard.inputComponents, this.wizard.model);
} }

View File

@@ -6,9 +6,10 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { WizardPageBase } from './wizardPageBase';
import { Model } from './model';
import { IToolsService } from '../services/toolsService'; import { IToolsService } from '../services/toolsService';
import { Model } from './model';
import { WizardPageBase } from './wizardPageBase';
import { WizardPageInfo } from './wizardPageInfo';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
export abstract class WizardBase<T, P extends WizardPageBase<T>, M extends Model> { export abstract class WizardBase<T, P extends WizardPageBase<T>, M extends Model> {
@@ -21,37 +22,55 @@ export abstract class WizardBase<T, P extends WizardPageBase<T>, M extends Model
return this._model; return this._model;
} }
constructor(private title: string, name: string, private _model: M, public toolsService: IToolsService) { protected get useGenerateScriptButton(): boolean {
return this._useGenerateScriptButton;
}
constructor(private title: string, name: string, private _model: M, public toolsService: IToolsService, private _useGenerateScriptButton: boolean = false) {
this.wizardObject = azdata.window.createWizard(title, name); this.wizardObject = azdata.window.createWizard(title, name);
} }
public async open(): Promise<void> { public async open(): Promise<void> {
this.initialize(); this.initialize();
this.wizardObject.generateScriptButton.hidden = true; // by default generateScriptButton stays hidden.
this.wizardObject.customButtons = this.customButtons; this.wizardObject.customButtons = this.customButtons;
this.toDispose.push(this.wizardObject.onPageChanged(async (e) => { this.toDispose.push(this.wizardObject.onPageChanged(async (e) => {
let previousPage = this.pages[e.lastPage]; let previousPage = this.pages[e.lastPage];
let newPage = this.pages[e.newPage]; let newPage = this.pages[e.newPage];
await previousPage.onLeave(); //if we are changing to the first page from no page before, essentially when we load the wizard for the first time, e.lastPage is -1 and previousPage is undefined.
await newPage.onEnter(); await previousPage?.onLeave(new WizardPageInfo(e.lastPage, this.pages.length));
if (this.useGenerateScriptButton) {
if (newPage === this.pages.slice(-1)[0]) {
// if newPage is the last page
this.wizardObject.generateScriptButton.hidden = false; //un-hide generateScriptButton on last page
} else {
// if newPage is not the last page
this.wizardObject.generateScriptButton.hidden = true; //hide generateScriptButton if it is not the last page
}
}
await newPage.onEnter(new WizardPageInfo(e.newPage, this.pages.length));
})); }));
this.toDispose.push(this.wizardObject.doneButton.onClick(async () => { this.toDispose.push(this.wizardObject.doneButton.onClick(async () => {
await this.onOk(); await this.onOk();
this.dispose(); this.dispose();
})); }));
this.toDispose.push(this.wizardObject.generateScriptButton.onClick(async () => {
await this.onGenerateScript();
this.dispose();
this.wizardObject.close(); // close the wizard. This is already hooked up into doneButton, so it is not needed for that button above.
}));
this.toDispose.push(this.wizardObject.cancelButton.onClick(() => { this.toDispose.push(this.wizardObject.cancelButton.onClick(() => {
this.onCancel(); this.onCancel();
this.dispose(); this.dispose();
})); }));
await this.wizardObject.open(); await this.wizardObject.open();
if (this.pages && this.pages.length > 0) {
await this.pages[0].onEnter();
}
} }
protected abstract initialize(): void; protected abstract initialize(): void;
protected abstract async onOk(): Promise<void>; protected abstract async onOk(): Promise<void>;
protected async onGenerateScript(): Promise<void> { }
protected abstract onCancel(): void; protected abstract onCancel(): void;
public addButton(button: azdata.window.Button) { public addButton(button: azdata.window.Button) {
@@ -62,11 +81,15 @@ export abstract class WizardBase<T, P extends WizardPageBase<T>, M extends Model
this.wizardObject!.pages = pages.map(p => p.pageObject); this.wizardObject!.pages = pages.map(p => p.pageObject);
this.pages = pages; this.pages = pages;
this.pages.forEach((page) => { this.pages.forEach((page) => {
page.pageObject.onValidityChanged((isValid: boolean) => {
// generateScriptButton is enabled only when the page is valid.
this.wizardObject.generateScriptButton.enabled = isValid;
});
page.initialize(); page.initialize();
}); });
} }
private dispose() { protected dispose() {
let errorOccurred = false; let errorOccurred = false;
this.toDispose.forEach((disposable: vscode.Disposable) => { this.toDispose.forEach((disposable: vscode.Disposable) => {
try { try {

View File

@@ -5,8 +5,10 @@
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { Validator } from './modelViewUtils'; import { Validator } from './modelViewUtils';
import { WizardPageInfo } from './wizardPageInfo';
export abstract class WizardPageBase<T> { export abstract class WizardPageBase<T> {
private _page: azdata.window.WizardPage; private _page: azdata.window.WizardPage;
private _validators: Validator[] = []; private _validators: Validator[] = [];
@@ -23,9 +25,9 @@ export abstract class WizardPageBase<T> {
return this._wizard; return this._wizard;
} }
public async onEnter(): Promise<void> { } public async onEnter(_pageInfo?: WizardPageInfo): Promise<void> { }
public async onLeave(): Promise<void> { } public async onLeave(_pageInfo?: WizardPageInfo): Promise<void> { }
public abstract initialize(): void; public abstract initialize(): void;

View File

@@ -0,0 +1,26 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export class WizardPageInfo {
public get pageCount(): number {
return this._pageCount;
}
public get currentPageId(): number {
return this._currentPageId;
}
public get isFirstPage(): boolean {
return this._currentPageId === 0;
}
public get isLastPage(): boolean {
return this._currentPageId === this._pageCount - 1;
}
constructor(private _currentPageId: number, private _pageCount: number) {
}
}