mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 01:25:39 -05:00
Dialog with custom UI API (#561)
* initial checkin for dialog with custom UI API
This commit is contained in:
@@ -410,6 +410,10 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
}
|
||||
}
|
||||
|
||||
protected get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the icon title class name
|
||||
* @param iconClassName
|
||||
|
||||
173
src/sql/base/browser/ui/modal/webViewDialog.ts
Normal file
173
src/sql/base/browser/ui/modal/webViewDialog.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 'vs/css!sql/media/icons/common-icons';
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import { Modal } from 'sql/base/browser/ui/modal/modal';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { attachButtonStyler, attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { localize } from 'vs/nls';
|
||||
import WebView from 'vs/workbench/parts/html/browser/webview';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import data = require('data');
|
||||
|
||||
export class WebViewDialog extends Modal {
|
||||
|
||||
private _body: HTMLElement;
|
||||
private _okButton: Button;
|
||||
private _okLabel: string;
|
||||
private _closeLabel: string;
|
||||
private _webview: WebView;
|
||||
private _html: string;
|
||||
private _headerTitle: string;
|
||||
|
||||
private _onOk = new Emitter<void>();
|
||||
public onOk: Event<void> = this._onOk.event;
|
||||
private _onClosed = new Emitter<void>();
|
||||
public onClosed: Event<void> = this._onClosed.event;
|
||||
private contentDisposables: IDisposable[] = [];
|
||||
private _onMessage = new Emitter<any>();
|
||||
|
||||
constructor(
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IClipboardService private _clipboardService: IClipboardService,
|
||||
@IPartService private _webViewPartService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IEnvironmentService private _environmentService: IEnvironmentService,
|
||||
) {
|
||||
super('', TelemetryKeys.WebView, _webViewPartService, telemetryService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
this._okLabel = localize('OK', 'OK');
|
||||
this._closeLabel = localize('close', 'Close');
|
||||
}
|
||||
|
||||
public set html(value: string) {
|
||||
this._html = value;
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
return this._html;
|
||||
}
|
||||
|
||||
public set okTitle(value: string) {
|
||||
this._okLabel = value;
|
||||
}
|
||||
|
||||
public get okTitle(): string {
|
||||
return this._okLabel;
|
||||
}
|
||||
|
||||
public set closeTitle(value: string) {
|
||||
this._closeLabel = value;
|
||||
}
|
||||
|
||||
public get closeTitle(): string {
|
||||
return this._closeLabel;
|
||||
}
|
||||
|
||||
public set headerTitle(value: string) {
|
||||
this._headerTitle = value
|
||||
}
|
||||
|
||||
public get headerTitle(): string {
|
||||
return this._headerTitle;
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
new Builder(container).div({ 'class': 'webview-dialog' }, (bodyBuilder) => {
|
||||
this._body = bodyBuilder.getHTMLElement();
|
||||
this._webview = new WebView(this._body, this._webViewPartService.getContainer(Parts.EDITOR_PART),
|
||||
this._contextViewService,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
allowScripts: true,
|
||||
enableWrappedPostMessage: true,
|
||||
hideFind: true
|
||||
}
|
||||
);
|
||||
|
||||
this._webview.style(this._themeService.getTheme());
|
||||
|
||||
this._webview.onMessage(message => {
|
||||
this._onMessage.fire(message);
|
||||
}, null, this.contentDisposables);
|
||||
|
||||
this._themeService.onThemeChange(theme => this._webview.style(theme), null, this.contentDisposables);
|
||||
|
||||
this.contentDisposables.push(this._webview);
|
||||
this.contentDisposables.push(toDisposable(() => this._webview = null));
|
||||
});
|
||||
}
|
||||
|
||||
get onMessage(): Event<any> {
|
||||
return this._onMessage.event;
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render();
|
||||
this._register(attachModalDialogStyler(this, this._themeService));
|
||||
|
||||
this._okButton = this.addFooterButton(this._okLabel, () => this.ok());
|
||||
this._register(attachButtonStyler(this._okButton, this._themeService));
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
// Nothing to re-layout
|
||||
}
|
||||
|
||||
private updateDialogBody(): void {
|
||||
this._webview.contents = [this.html];
|
||||
}
|
||||
|
||||
/* espace key */
|
||||
protected onClose() {
|
||||
this.ok();
|
||||
}
|
||||
|
||||
/* enter key */
|
||||
protected onAccept() {
|
||||
this.ok();
|
||||
}
|
||||
|
||||
public ok(): void {
|
||||
this._onOk.fire();
|
||||
this.close();
|
||||
}
|
||||
|
||||
public close() {
|
||||
this.hide();
|
||||
this._onClosed.fire();
|
||||
}
|
||||
|
||||
public sendMessage(message: any): void {
|
||||
this._webview.sendMessage(message);
|
||||
}
|
||||
|
||||
public open() {
|
||||
this.title = this.headerTitle;
|
||||
this.updateDialogBody();
|
||||
this.show();
|
||||
this._okButton.focus();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.contentDisposables.forEach(element => {
|
||||
element.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ export const FirewallRuleRequested = 'FirewallRuleCreated';
|
||||
|
||||
// Modal Dialogs:
|
||||
export const ErrorMessage = 'ErrorMessage';
|
||||
export const WebView = 'WebView';
|
||||
export const ConnectionAdvancedProperties = 'ConnectionAdvancedProperties';
|
||||
export const Connection = 'Connection';
|
||||
export const Backup = 'Backup';
|
||||
|
||||
59
src/sql/data.d.ts
vendored
59
src/sql/data.d.ts
vendored
@@ -1360,4 +1360,63 @@ declare module 'data' {
|
||||
result: boolean;
|
||||
ipAddress: string;
|
||||
}
|
||||
|
||||
export interface ModalDialog {
|
||||
/**
|
||||
* Title of the webview.
|
||||
*/
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* Contents of the dialog body.
|
||||
*/
|
||||
html: string;
|
||||
|
||||
/**
|
||||
* The caption of the OK button.
|
||||
*/
|
||||
okTitle: string;
|
||||
|
||||
/**
|
||||
* The caption of the Close button.
|
||||
*/
|
||||
closeTitle: string;
|
||||
|
||||
/**
|
||||
* Opens the dialog.
|
||||
*/
|
||||
open(): void;
|
||||
|
||||
/**
|
||||
* Closes the dialog.
|
||||
*/
|
||||
close(): void;
|
||||
|
||||
/**
|
||||
* Raised when the webview posts a message.
|
||||
*/
|
||||
readonly onMessage: vscode.Event<any>;
|
||||
|
||||
/**
|
||||
* Raised when dialog closed.
|
||||
*/
|
||||
readonly onClosed: vscode.Event<any>;
|
||||
|
||||
/**
|
||||
* Post a message to the dialog.
|
||||
*
|
||||
* @param message Body of the message.
|
||||
*/
|
||||
postMessage(message: any): Thenable<any>;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
/**
|
||||
* creates a dialog
|
||||
* @param title
|
||||
*/
|
||||
export function createDialog(
|
||||
title: string
|
||||
): ModalDialog;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import { WebViewDialog } from 'sql/base/browser/ui/modal/webViewDialog';
|
||||
|
||||
import { MainThreadModalDialogShape, SqlMainContext, SqlExtHostContext, ExtHostModalDialogsShape } from 'sql/workbench/api/node/sqlextHost.protocol';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadModalDialog)
|
||||
export class MainThreadModalDialog implements MainThreadModalDialogShape {
|
||||
private readonly _proxy: ExtHostModalDialogsShape;
|
||||
private readonly _dialogs = new Map<number, WebViewDialog>();
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IWorkbenchEditorService private readonly _editorService: IWorkbenchEditorService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
) {
|
||||
this._proxy = context.get(SqlExtHostContext.ExtHostModalDialogs);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
$createDialog(handle: number): void {
|
||||
const dialog = this._instantiationService.createInstance(WebViewDialog);
|
||||
|
||||
this._dialogs.set(handle, dialog);
|
||||
dialog.onMessage(args => {
|
||||
this._proxy.$onMessage(handle, args);
|
||||
});
|
||||
|
||||
dialog.onClosed(args => {
|
||||
this._proxy.$onClosed(handle);
|
||||
});
|
||||
}
|
||||
|
||||
$disposeDialog(handle: number): void {
|
||||
const dialog = this._dialogs.get(handle);
|
||||
dialog.close();
|
||||
}
|
||||
|
||||
$setTitle(handle: number, value: string): void {
|
||||
const dialog = this._dialogs.get(handle);
|
||||
dialog.headerTitle = value;
|
||||
}
|
||||
|
||||
$setHtml(handle: number, value: string): void {
|
||||
const dialog = this._dialogs.get(handle);
|
||||
dialog.html = value;
|
||||
}
|
||||
|
||||
$show(handle: number): void {
|
||||
const dialog = this._dialogs.get(handle);
|
||||
dialog.render();
|
||||
dialog.open();
|
||||
}
|
||||
|
||||
async $sendMessage(handle: number, message: any): Promise<boolean> {
|
||||
const dialog = this._dialogs.get(handle);
|
||||
dialog.sendMessage(message);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import 'sql/workbench/api/electron-browser/mainThreadModalDialog';
|
||||
122
src/sql/workbench/api/node/extHostModalDialog.ts
Normal file
122
src/sql/workbench/api/node/extHostModalDialog.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { SqlMainContext, MainThreadModalDialogShape, ExtHostModalDialogsShape } from 'sql/workbench/api/node/sqlextHost.protocol';
|
||||
import { IMainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import * as data from 'data';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
class ExtHostDialog implements data.ModalDialog {
|
||||
private _title: string;
|
||||
private _html: string;
|
||||
private _okTitle: string;
|
||||
private _closeTitle: string;
|
||||
public onMessageEmitter = new Emitter<any>();
|
||||
public onClosedEmitter = new Emitter<any>();
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: MainThreadModalDialogShape,
|
||||
private readonly _handle: number,
|
||||
) { }
|
||||
|
||||
get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
set title(value: string) {
|
||||
if (this._title !== value) {
|
||||
this._title = value;
|
||||
this._proxy.$setTitle(this._handle, value);
|
||||
}
|
||||
}
|
||||
|
||||
get html(): string {
|
||||
return this._html;
|
||||
}
|
||||
|
||||
set html(value: string) {
|
||||
if (this._html !== value) {
|
||||
this._html = value;
|
||||
this._proxy.$setHtml(this._handle, value);
|
||||
}
|
||||
}
|
||||
|
||||
public set okTitle(value: string) {
|
||||
this._okTitle = value;
|
||||
}
|
||||
|
||||
public get okTitle(): string {
|
||||
return this._okTitle;
|
||||
}
|
||||
|
||||
public set closeTitle(value: string) {
|
||||
this._closeTitle = value;
|
||||
}
|
||||
|
||||
public get closeTitle(): string {
|
||||
return this._closeTitle;
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this._proxy.$show(this._handle);
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._proxy.$disposeDialog(this._handle);
|
||||
}
|
||||
|
||||
public postMessage(message: any): Thenable<any> {
|
||||
return this._proxy.$sendMessage(this._handle, message);
|
||||
}
|
||||
|
||||
public get onMessage(): vscode.Event<any> {
|
||||
return this.onMessageEmitter.event;
|
||||
}
|
||||
|
||||
public get onClosed(): vscode.Event<any> {
|
||||
return this.onClosedEmitter.event;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostModalDialogs implements ExtHostModalDialogsShape {
|
||||
private static _handlePool = 0;
|
||||
|
||||
private readonly _proxy: MainThreadModalDialogShape;
|
||||
|
||||
private readonly _webviews = new Map<number, ExtHostDialog>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext
|
||||
) {
|
||||
this._proxy = mainContext.get(SqlMainContext.MainThreadModalDialog);
|
||||
}
|
||||
|
||||
createDialog(
|
||||
title: string
|
||||
): data.ModalDialog {
|
||||
console.log(title);
|
||||
const handle = ExtHostModalDialogs._handlePool++;
|
||||
this._proxy.$createDialog(handle);
|
||||
|
||||
const webview = new ExtHostDialog(this._proxy, handle);
|
||||
this._webviews.set(handle, webview);
|
||||
webview.title = title;
|
||||
//webview.options = options;
|
||||
//this._proxy.$show(handle);
|
||||
return webview;
|
||||
}
|
||||
|
||||
$onMessage(handle: number, message: any): void {
|
||||
const webview = this._webviews.get(handle);
|
||||
webview.onMessageEmitter.fire(message);
|
||||
}
|
||||
|
||||
$onClosed(handle: number): void {
|
||||
const webview = this._webviews.get(handle);
|
||||
webview.onClosedEmitter.fire();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { ExtHostThreadService } from 'vs/workbench/services/thread/node/extHostT
|
||||
import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostModalDialogs } from 'sql/workbench/api/node/extHostModalDialog';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
|
||||
@@ -52,6 +53,7 @@ export function createApiFactory(
|
||||
const extHostDataProvider = threadService.set(SqlExtHostContext.ExtHostDataProtocol, new ExtHostDataProtocol(threadService));
|
||||
const extHostSerializationProvider = threadService.set(SqlExtHostContext.ExtHostSerializationProvider, new ExtHostSerializationProvider(threadService));
|
||||
const extHostResourceProvider = threadService.set(SqlExtHostContext.ExtHostResourceProvider, new ExtHostResourceProvider(threadService));
|
||||
const extHostModalDialogs = threadService.set(SqlExtHostContext.ExtHostModalDialogs, new ExtHostModalDialogs(threadService));
|
||||
|
||||
return {
|
||||
vsCodeFactory: vsCodeFactory,
|
||||
@@ -236,6 +238,12 @@ export function createApiFactory(
|
||||
}
|
||||
};
|
||||
|
||||
const window = {
|
||||
createDialog(name: string) {
|
||||
return extHostModalDialogs.createDialog(name);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
accounts,
|
||||
credentials,
|
||||
@@ -248,7 +256,8 @@ export function createApiFactory(
|
||||
MetadataType: sqlExtHostTypes.MetadataType,
|
||||
TaskStatus: sqlExtHostTypes.TaskStatus,
|
||||
TaskExecutionMode: sqlExtHostTypes.TaskExecutionMode,
|
||||
ScriptOperation: sqlExtHostTypes.ScriptOperation
|
||||
ScriptOperation: sqlExtHostTypes.ScriptOperation,
|
||||
window
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -409,7 +409,8 @@ export const SqlMainContext = {
|
||||
MainThreadCredentialManagement: createMainId<MainThreadCredentialManagementShape>('MainThreadCredentialManagement'),
|
||||
MainThreadDataProtocol: createMainId<MainThreadDataProtocolShape>('MainThreadDataProtocol'),
|
||||
MainThreadSerializationProvider: createMainId<MainThreadSerializationProviderShape>('MainThreadSerializationProvider'),
|
||||
MainThreadResourceProvider: createMainId<MainThreadResourceProviderShape>('MainThreadResourceProvider')
|
||||
MainThreadResourceProvider: createMainId<MainThreadResourceProviderShape>('MainThreadResourceProvider'),
|
||||
MainThreadModalDialog: createMainId<MainThreadModalDialogShape>('MainThreadModalDialog'),
|
||||
};
|
||||
|
||||
export const SqlExtHostContext = {
|
||||
@@ -417,5 +418,19 @@ export const SqlExtHostContext = {
|
||||
ExtHostCredentialManagement: createExtId<ExtHostCredentialManagementShape>('ExtHostCredentialManagement'),
|
||||
ExtHostDataProtocol: createExtId<ExtHostDataProtocolShape>('ExtHostDataProtocol'),
|
||||
ExtHostSerializationProvider: createExtId<ExtHostSerializationProviderShape>('ExtHostSerializationProvider'),
|
||||
ExtHostResourceProvider: createExtId<ExtHostResourceProviderShape>('ExtHostResourceProvider')
|
||||
ExtHostResourceProvider: createExtId<ExtHostResourceProviderShape>('ExtHostResourceProvider'),
|
||||
ExtHostModalDialogs: createExtId<ExtHostModalDialogsShape>('ExtHostModalDialogs')
|
||||
};
|
||||
|
||||
export interface MainThreadModalDialogShape extends IDisposable {
|
||||
$createDialog(handle: number): void;
|
||||
$disposeDialog(handle: number): void;
|
||||
$show(handle: number): void;
|
||||
$setTitle(handle: number, value: string): void;
|
||||
$setHtml(handle: number, value: string): void;
|
||||
$sendMessage(handle: number, value: any): Thenable<boolean>;
|
||||
}
|
||||
export interface ExtHostModalDialogsShape {
|
||||
$onMessage(handle: number, message: any): void;
|
||||
$onClosed(handle: number): void;
|
||||
}
|
||||
Reference in New Issue
Block a user