diff --git a/samples/sqlservices/package.json b/samples/sqlservices/package.json index d4b46964e0..241c16b1b9 100644 --- a/samples/sqlservices/package.json +++ b/samples/sqlservices/package.json @@ -16,6 +16,11 @@ ], "main": "./out/src/extension", "contributes": { + + "commands": [{ + "command": "mssql.openDialog", + "title": "mssql.openDialog" + }], "dashboard.tabs": [ { "id": "sqlservices.tab", @@ -62,7 +67,9 @@ "postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/sqlops/bin/install && gulp copytypings" }, "dependencies": { - "vscode-nls": "^3.2.2" + "vscode-nls": "^3.2.2", + "fs-extra": "^5.0.0", + "handlebars": "^4.0.11" }, "devDependencies": { "@types/node": "^7.0.43", @@ -76,6 +83,7 @@ "sqlops": "github:anthonydresser/sqlops-extension-sqlops", "tslint": "^3.14.0", "typescript": "^2.6.1", - "vscode": "^1.1.14" + "vscode": "^1.1.14", + "@types/handlebars": "^4.0.11" } } diff --git a/samples/sqlservices/src/controllers/mainController.ts b/samples/sqlservices/src/controllers/mainController.ts index 5974a55a8e..f1eb306e0b 100644 --- a/samples/sqlservices/src/controllers/mainController.ts +++ b/samples/sqlservices/src/controllers/mainController.ts @@ -40,11 +40,110 @@ export default class MainController implements vscode.Disposable { vscode.window.showInformationMessage(`Clicked from profile ${profile.serverName}.${profile.databaseName}`); }); + vscode.commands.registerCommand('mssql.openDialog', () => { + this.openDialog(); + }); + return Promise.resolve(true); } + private openDialog(): void { + let dialog = sqlops.window.modelviewdialog.createDialog('Test dialog'); + let tab1 = sqlops.window.modelviewdialog.createTab('Test tab 1'); + + let tab2 = sqlops.window.modelviewdialog.createTab('Test tab 2'); + tab2.content = 'sqlservices'; + dialog.content = [tab1, tab2]; + dialog.okButton.onClick(() => console.log('ok clicked!')); + dialog.cancelButton.onClick(() => console.log('cancel clicked!')); + dialog.okButton.label = 'ok'; + dialog.cancelButton.label = 'no'; + let customButton1 = sqlops.window.modelviewdialog.createButton('Test button 1'); + customButton1.onClick(() => console.log('button 1 clicked!')); + let customButton2 = sqlops.window.modelviewdialog.createButton('Test button 2'); + customButton2.onClick(() => console.log('button 2 clicked!')); + dialog.customButtons = [customButton1, customButton2]; + tab1.registerContent(async (view) => { + let inputBox = view.modelBuilder.inputBox() + .withProperties({ + //width: 300 + }) + .component(); + let inputBox2 = view.modelBuilder.inputBox() + .component(); + + let inputBox3 = view.modelBuilder.inputBox() + .component(); + + let checkbox = view.modelBuilder.checkBox() + .withProperties({ + label: 'Copy-only backup' + }) + .component(); + checkbox.onChanged(e => { + console.info("inputBox.enabled " + inputBox.enabled); + inputBox.enabled = !inputBox.enabled; + }); + let button = view.modelBuilder.button() + .withProperties({ + label: '+' + }).component(); + let button3 = view.modelBuilder.button() + .withProperties({ + label: '-' + + }).component(); + let button2 = view.modelBuilder.button() + .component(); + button.onDidClick(e => { + inputBox2.value = 'Button clicked'; + }); + let dropdown = view.modelBuilder.dropDown() + .withProperties({ + value: 'Full', + values: ['Full', 'Differential', 'Transaction Log'] + }) + .component(); + let f = 0; + inputBox.onTextChanged((params) => { + vscode.window.showInformationMessage(inputBox.value); + f = f + 1; + inputBox2.value=f.toString(); + }); + dropdown.onValueChanged((params) => { + vscode.window.showInformationMessage(inputBox2.value); + inputBox.value = dropdown.value; + }); + let formModel = view.modelBuilder.formContainer() + .withFormItems([{ + component: inputBox, + title: 'Backup name' + }, { + component: inputBox2, + title: 'Recovery model' + }, { + component:dropdown, + title: 'Backup type' + }, { + component: checkbox, + title: '' + }, { + component: inputBox2, + title: 'Backup files', + actions: [button, button3] + }], { + horizontal:false, + width: 500, + componentWidth: 400 + }).component(); + await view.initializeModel(formModel); + }); + + sqlops.window.modelviewdialog.openDialog(dialog); + } + private registerSqlServicesModelView(): void { - sqlops.dashboard.registerModelViewProvider('sqlservices', async (view) => { + sqlops.ui.registerModelViewProvider('sqlservices', async (view) => { let flexModel = view.modelBuilder.flexContainer() .withLayout({ flexFlow: 'row', @@ -62,7 +161,7 @@ export default class MainController implements vscode.Disposable { .withProperties({ label: 'label1', value: 'value1', - actions: [{ label: 'action', taskId: 'sqlservices.clickTask' }] + actions: [{ label: 'action' }] }) .component() ]).component(), @@ -74,7 +173,7 @@ export default class MainController implements vscode.Disposable { .withProperties({ label: 'label2', value: 'value2', - actions: [{ label: 'action', taskId: 'sqlservices.clickTask' }] + actions: [{ label: 'action' }] }) .component() ]).component() @@ -85,7 +184,7 @@ export default class MainController implements vscode.Disposable { } private registerSplitPanelModelView(): void { - sqlops.dashboard.registerModelViewProvider('splitPanel', async (view) => { + sqlops.ui.registerModelViewProvider('splitPanel', async (view) => { let numPanels = 3; let splitPanel = new SplitPropertiesPanel(view, numPanels); await view.initializeModel(splitPanel.modelBase); diff --git a/src/sql/platform/dialog/dialogTypes.ts b/src/sql/platform/dialog/dialogTypes.ts index 382710914a..2c44371ea8 100644 --- a/src/sql/platform/dialog/dialogTypes.ts +++ b/src/sql/platform/dialog/dialogTypes.ts @@ -9,7 +9,7 @@ import * as sqlops from 'sqlops'; import { localize } from 'vs/nls'; import Event, { Emitter } from 'vs/base/common/event'; -export class DialogTab implements sqlops.window.modelviewdialog.DialogTab { +export class DialogTab { public content: string; constructor(public title: string, content?: string) { @@ -19,7 +19,7 @@ export class DialogTab implements sqlops.window.modelviewdialog.DialogTab { } } -export class Dialog implements sqlops.window.modelviewdialog.Dialog { +export class Dialog { private static readonly DONE_BUTTON_LABEL = localize('dialogModalDoneButtonLabel', 'Done'); private static readonly CANCEL_BUTTON_LABEL = localize('dialogModalCancelButtonLabel', 'Cancel'); diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index dee720b59f..bfcd0db951 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -366,8 +366,21 @@ declare module 'sqlops' { */ export function closeDialog(dialog: Dialog): void; + export interface ModelViewPanel { + /** + * Register model view content for the dialog. + * Doesn't do anything if model view is already registered + */ + registerContent(handler: (view: ModelView) => void): void; + + /** + * Returns the model view content if registered. Returns undefined if model review is not registered + */ + readonly modelView: ModelView; + } + // Model view dialog classes - export interface Dialog { + export interface Dialog extends ModelViewPanel { /** * The title of the dialog */ @@ -405,7 +418,7 @@ declare module 'sqlops' { readonly onValidityChanged: vscode.Event; } - export interface DialogTab { + export interface DialogTab extends ModelViewPanel { /** * The title of the tab */ diff --git a/src/sql/workbench/api/node/extHostModelViewDialog.ts b/src/sql/workbench/api/node/extHostModelViewDialog.ts index f5dccd0ab7..d517e5faaa 100644 --- a/src/sql/workbench/api/node/extHostModelViewDialog.ts +++ b/src/sql/workbench/api/node/extHostModelViewDialog.ts @@ -12,10 +12,47 @@ import * as nls from 'vs/nls'; import * as vscode from 'vscode'; import * as sqlops from 'sqlops'; -import { SqlMainContext, ExtHostModelViewDialogShape, MainThreadModelViewDialogShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; +import { SqlMainContext, ExtHostModelViewDialogShape, MainThreadModelViewDialogShape, ExtHostModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes'; -class DialogImpl implements sqlops.window.modelviewdialog.Dialog { +class ModelViewPanelImpl implements sqlops.window.modelviewdialog.ModelViewPanel { + private _modelView: sqlops.ModelView; + private _handle: number; + private _modelViewId: string; + + constructor(private _viewType: string, + protected _extHostModelView: ExtHostModelViewShape) { + } + + public registerContent(handler: (view: sqlops.ModelView) => void): void { + if (!this._modelViewId) { + let viewId = this._viewType + this.handle; + this.setModelViewId(viewId); + this._extHostModelView.$registerProvider(viewId, modelView => { + this._modelView = modelView; + handler(modelView); + }); + } + } + + public set handle(value: number) { + this._handle = value; + } + + public setModelViewId(value: string) { + this._modelViewId = value; + } + + public get modelView(): sqlops.ModelView { + return this._modelView; + } + + public set modelView(value: sqlops.ModelView) { + this._modelView = value; + } +} + +class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.Dialog { public title: string; public content: string | sqlops.window.modelviewdialog.DialogTab[]; public okButton: sqlops.window.modelviewdialog.Button; @@ -24,7 +61,10 @@ class DialogImpl implements sqlops.window.modelviewdialog.Dialog { public readonly onValidityChanged: vscode.Event; private _valid: boolean = true; - constructor(private _extHostModelViewDialog: ExtHostModelViewDialog) { + + constructor(private _extHostModelViewDialog: ExtHostModelViewDialog, + extHostModelView: ExtHostModelViewShape) { + super('modelViewDialog', extHostModelView); this.okButton = this._extHostModelViewDialog.createButton(nls.localize('dialogOkLabel', 'Done')); this.cancelButton = this._extHostModelViewDialog.createButton(nls.localize('dialogCancelLabel', 'Cancel')); this.onValidityChanged = this._extHostModelViewDialog.getValidityChangedEvent(this); @@ -34,13 +74,28 @@ class DialogImpl implements sqlops.window.modelviewdialog.Dialog { public get valid(): boolean { return this._valid; } + + public setModelViewId(value: string) { + super.setModelViewId(value); + this.content = value; + } } -class TabImpl implements sqlops.window.modelviewdialog.DialogTab { +class TabImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.DialogTab { + constructor( + private _extHostModelViewDialog: ExtHostModelViewDialog, + extHostModelView: ExtHostModelViewShape) { + super('modelViewDialogTab', extHostModelView); + } + public title: string; public content: string; + public handle: number; - constructor(private _extHostModelViewDialog: ExtHostModelViewDialog) { } + public setModelViewId(value: string) { + super.setModelViewId(value); + this.content = value; + } } class ButtonImpl implements sqlops.window.modelviewdialog.Button { @@ -101,7 +156,8 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape { private readonly _onClickCallbacks = new Map void>(); constructor( - mainContext: IMainContext + mainContext: IMainContext, + private _extHostModelView: ExtHostModelViewShape ) { this._proxy = mainContext.getProxy(SqlMainContext.MainThreadModelViewDialog); } @@ -204,16 +260,16 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape { } public createDialog(title: string): sqlops.window.modelviewdialog.Dialog { - let dialog = new DialogImpl(this); + let dialog = new DialogImpl(this, this._extHostModelView); dialog.title = title; - this.getDialogHandle(dialog); + dialog.handle = this.getDialogHandle(dialog); return dialog; } public createTab(title: string): sqlops.window.modelviewdialog.DialogTab { - let tab = new TabImpl(this); + let tab = new TabImpl(this, this._extHostModelView); tab.title = title; - this.getTabHandle(tab); + tab.handle = this.getTabHandle(tab); return tab; } diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index f904642a9e..f9d0cd578b 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -66,7 +66,7 @@ export function createApiFactory( const extHostWebviewWidgets = rpcProtocol.set(SqlExtHostContext.ExtHostDashboardWebviews, new ExtHostDashboardWebviews(rpcProtocol)); const extHostModelView = rpcProtocol.set(SqlExtHostContext.ExtHostModelView, new ExtHostModelView(rpcProtocol)); const extHostDashboard = rpcProtocol.set(SqlExtHostContext.ExtHostDashboard, new ExtHostDashboard(rpcProtocol)); - const extHostModelViewDialog = rpcProtocol.set(SqlExtHostContext.ExtHostModelViewDialog, new ExtHostModelViewDialog(rpcProtocol)); + const extHostModelViewDialog = rpcProtocol.set(SqlExtHostContext.ExtHostModelViewDialog, new ExtHostModelViewDialog(rpcProtocol, extHostModelView)); const extHostQueryEditor = rpcProtocol.set(SqlExtHostContext.ExtHostQueryEditor, new ExtHostQueryEditor(rpcProtocol)); diff --git a/src/sqltest/workbench/api/extHostModelViewDialog.test.ts b/src/sqltest/workbench/api/extHostModelViewDialog.test.ts index ef492f2dc1..8e7d4377af 100644 --- a/src/sqltest/workbench/api/extHostModelViewDialog.test.ts +++ b/src/sqltest/workbench/api/extHostModelViewDialog.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { Mock, It, Times } from 'typemoq'; import { ExtHostModelViewDialog } from 'sql/workbench/api/node/extHostModelViewDialog'; -import { MainThreadModelViewDialogShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; +import { MainThreadModelViewDialogShape, ExtHostModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; import { IMainContext } from 'vs/workbench/api/node/extHost.protocol'; 'use strict'; @@ -14,6 +14,7 @@ import { IMainContext } from 'vs/workbench/api/node/extHost.protocol'; suite('ExtHostModelViewDialog Tests', () => { let extHostModelViewDialog: ExtHostModelViewDialog; let mockProxy: Mock; + let extHostModelView: Mock; setup(() => { mockProxy = Mock.ofInstance({ @@ -26,7 +27,11 @@ suite('ExtHostModelViewDialog Tests', () => { let mainContext = { getProxy: proxyType => mockProxy.object }; - extHostModelViewDialog = new ExtHostModelViewDialog(mainContext); + + extHostModelView = Mock.ofInstance( { + $registerProvider: (widget, handler) => undefined + }); + extHostModelViewDialog = new ExtHostModelViewDialog(mainContext, extHostModelView.object); }); test('Creating a dialog returns a dialog with initialized ok and cancel buttons and the given title', () => {