mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Initial work for custom model view dialogs (#1183)
This commit is contained in:
@@ -64,6 +64,10 @@ export class ModelViewContent extends ViewBase implements OnInit, IModelView {
|
|||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
public get connection(): sqlops.connection.Connection {
|
public get connection(): sqlops.connection.Connection {
|
||||||
|
if (!this._commonService.connectionManagementService) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
let currentConnection = this._commonService.connectionManagementService.connectionInfo.connectionProfile;
|
let currentConnection = this._commonService.connectionManagementService.connectionInfo.connectionProfile;
|
||||||
let connection: sqlops.connection.Connection = {
|
let connection: sqlops.connection.Connection = {
|
||||||
providerName: currentConnection.providerName,
|
providerName: currentConnection.providerName,
|
||||||
@@ -75,6 +79,10 @@ export class ModelViewContent extends ViewBase implements OnInit, IModelView {
|
|||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
public get serverInfo(): sqlops.ServerInfo {
|
public get serverInfo(): sqlops.ServerInfo {
|
||||||
|
if (!this._commonService.connectionManagementService) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return this._commonService.connectionManagementService.connectionInfo.serverInfo;
|
return this._commonService.connectionManagementService.connectionInfo.serverInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/sql/platform/dialog/customDialogService.ts
Normal file
25
src/sql/platform/dialog/customDialogService.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 sqlops from 'sqlops';
|
||||||
|
import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog';
|
||||||
|
import { DialogModal } from 'sql/platform/dialog/dialogModal';
|
||||||
|
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||||
|
import { IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
|
const defaultOptions: IModalOptions = { hasBackButton: true, isWide: true };
|
||||||
|
|
||||||
|
export class CustomDialogService {
|
||||||
|
constructor( @IInstantiationService private _instantiationService: IInstantiationService) { }
|
||||||
|
|
||||||
|
public showDialog(dialog: Dialog, options?: IModalOptions): void {
|
||||||
|
let optionsDialog = this._instantiationService.createInstance(DialogModal, dialog, 'CustomDialog', options || defaultOptions);
|
||||||
|
optionsDialog.render();
|
||||||
|
optionsDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
57
src/sql/platform/dialog/dialog.module.ts
Normal file
57
src/sql/platform/dialog/dialog.module.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./media/dialogModal';
|
||||||
|
|
||||||
|
import { forwardRef, NgModule, ComponentFactoryResolver, Inject, ApplicationRef } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { DialogContainer } from 'sql/platform/dialog/dialogContainer.component';
|
||||||
|
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||||
|
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||||
|
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||||
|
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||||
|
import { BOOTSTRAP_SERVICE_ID, IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
|
/* Model-backed components */
|
||||||
|
let extensionComponents = Registry.as<IComponentRegistry>(Extensions.ComponentContribution).getAllCtors();
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
DialogContainer,
|
||||||
|
ModelViewContent,
|
||||||
|
ModelComponentWrapper,
|
||||||
|
ComponentHostDirective,
|
||||||
|
...extensionComponents
|
||||||
|
],
|
||||||
|
entryComponents: [DialogContainer, ...extensionComponents],
|
||||||
|
imports: [
|
||||||
|
FormsModule,
|
||||||
|
CommonModule,
|
||||||
|
BrowserModule
|
||||||
|
],
|
||||||
|
providers: [{ provide: APP_BASE_HREF, useValue: '/' }, CommonServiceInterface]
|
||||||
|
})
|
||||||
|
export class DialogModule {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
|
||||||
|
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService,
|
||||||
|
@Inject(forwardRef(() => CommonServiceInterface)) bootstrap: CommonServiceInterface,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngDoBootstrap(appRef: ApplicationRef) {
|
||||||
|
const factoryWrapper: any = this._resolver.resolveComponentFactory(DialogContainer);
|
||||||
|
const uniqueSelector: string = this._bootstrapService.getUniqueSelector('dialog-modelview-container');
|
||||||
|
factoryWrapper.factory.selector = uniqueSelector;
|
||||||
|
appRef.bootstrap(factoryWrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/sql/platform/dialog/dialogContainer.component.ts
Normal file
45
src/sql/platform/dialog/dialogContainer.component.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./media/dialogModal';
|
||||||
|
import { Component, AfterContentInit, ViewChild, Input, Inject, forwardRef, ElementRef } from '@angular/core';
|
||||||
|
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||||
|
import { BootstrapParams } from 'sql/services/bootstrap/bootstrapParams';
|
||||||
|
import { BOOTSTRAP_SERVICE_ID, IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
export interface DialogComponentParams extends BootstrapParams {
|
||||||
|
modelViewId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'dialog-modelview-container',
|
||||||
|
providers: [],
|
||||||
|
template: `
|
||||||
|
<modelview-content [modelViewId]="modelViewId">
|
||||||
|
</modelview-content>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class DialogContainer implements AfterContentInit {
|
||||||
|
private _onResize = new Emitter<void>();
|
||||||
|
public readonly onResize: Event<void> = this._onResize.event;
|
||||||
|
|
||||||
|
public modelViewId: string;
|
||||||
|
@ViewChild(ModelViewContent) private _modelViewContent: ModelViewContent;
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
||||||
|
@Inject(BOOTSTRAP_SERVICE_ID) bootstrapService: IBootstrapService) {
|
||||||
|
this.modelViewId = (bootstrapService.getBootstrapParams(el.nativeElement.tagName) as DialogComponentParams).modelViewId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(): void {
|
||||||
|
this._modelViewContent.layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/sql/platform/dialog/dialogModal.ts
Normal file
105
src/sql/platform/dialog/dialogModal.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./media/dialogModal';
|
||||||
|
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||||
|
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||||
|
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||||
|
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||||
|
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { Builder } from 'vs/base/browser/builder';
|
||||||
|
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||||
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
|
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { Button } from 'vs/base/browser/ui/button/button';
|
||||||
|
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
|
export class DialogModal extends Modal {
|
||||||
|
private static readonly DONE_BUTTON_LABEL = localize('dialogModalDoneButtonLabel', 'Done');
|
||||||
|
private static readonly CANCEL_BUTTON_LABEL = localize('dialogModalCancelButtonLabel', 'Cancel');
|
||||||
|
|
||||||
|
private _dialogPane: DialogPane;
|
||||||
|
|
||||||
|
// Wizard HTML elements
|
||||||
|
private _body: HTMLElement;
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
private _cancelButton: Button;
|
||||||
|
private _doneButton: Button;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _dialog: Dialog,
|
||||||
|
name: string,
|
||||||
|
options: IModalOptions,
|
||||||
|
@IPartService partService: IPartService,
|
||||||
|
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
||||||
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
|
@IBootstrapService private _bootstrapService: IBootstrapService
|
||||||
|
) {
|
||||||
|
super(_dialog.title, name, partService, telemetryService, contextKeyService, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
super.render();
|
||||||
|
attachModalDialogStyler(this, this._themeService);
|
||||||
|
|
||||||
|
if (this.backButton) {
|
||||||
|
this.backButton.onDidClick(() => this.cancel());
|
||||||
|
attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND });
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cancelButton = this.addFooterButton(DialogModal.CANCEL_BUTTON_LABEL, () => this.cancel());
|
||||||
|
this._doneButton = this.addFooterButton(DialogModal.DONE_BUTTON_LABEL, () => this.done());
|
||||||
|
attachButtonStyler(this._cancelButton, this._themeService);
|
||||||
|
attachButtonStyler(this._doneButton, this._themeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected renderBody(container: HTMLElement): void {
|
||||||
|
new Builder(container).div({ class: 'dialogModal-body' }, (bodyBuilder) => {
|
||||||
|
this._body = bodyBuilder.getHTMLElement();
|
||||||
|
});
|
||||||
|
|
||||||
|
this._dialogPane = new DialogPane(this._dialog, this._bootstrapService);
|
||||||
|
this._dialogPane.createBody(this._body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public open(): void {
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public done(): void {
|
||||||
|
this.dispose();
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public cancel(): void {
|
||||||
|
this.dispose();
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected hide(): void {
|
||||||
|
super.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected show(): void {
|
||||||
|
super.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
super.dispose();
|
||||||
|
this._dialogPane.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/sql/platform/dialog/dialogPane.ts
Normal file
95
src/sql/platform/dialog/dialogPane.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./media/dialogModal';
|
||||||
|
import { NgModuleRef } from '@angular/core';
|
||||||
|
import { IModalDialogStyles } from 'sql/base/browser/ui/modal/modal';
|
||||||
|
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||||
|
import { TabbedPanel, IPanelTab, IPanelView } from 'sql/base/browser/ui/panel/panel';
|
||||||
|
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { DialogModule } from 'sql/platform/dialog/dialog.module';
|
||||||
|
import { DialogComponentParams } from 'sql/platform/dialog/dialogContainer.component';
|
||||||
|
import { Builder } from 'vs/base/browser/builder';
|
||||||
|
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
|
export class DialogPane extends Disposable implements IThemable {
|
||||||
|
private _activeTabIndex: number;
|
||||||
|
private _tabbedPanel: TabbedPanel;
|
||||||
|
private _moduleRef: NgModuleRef<{}>;
|
||||||
|
|
||||||
|
// HTML Elements
|
||||||
|
private _body: HTMLElement;
|
||||||
|
private _tabBar: HTMLElement;
|
||||||
|
private _tabs: HTMLElement[];
|
||||||
|
private _tabContent: HTMLElement[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private _dialog: Dialog,
|
||||||
|
private _bootstrapService: IBootstrapService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this._tabs = [];
|
||||||
|
this._tabContent = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public createBody(container: HTMLElement): HTMLElement {
|
||||||
|
new Builder(container).div({ class: 'dialogModal-pane' }, (bodyBuilder) => {
|
||||||
|
this._body = bodyBuilder.getHTMLElement();
|
||||||
|
if (typeof this._dialog.content === 'string' || this._dialog.content.length < 2) {
|
||||||
|
let modelViewId = typeof this._dialog.content === 'string' ? this._dialog.content : this._dialog.content[0].content;
|
||||||
|
this.initializeModelViewContainer(this._body, modelViewId);
|
||||||
|
} else {
|
||||||
|
this._tabbedPanel = new TabbedPanel(this._body);
|
||||||
|
this._dialog.content.forEach((tab, tabIndex) => {
|
||||||
|
this._tabbedPanel.pushTab({
|
||||||
|
title: tab.title,
|
||||||
|
identifier: 'dialogPane.' + this._dialog.title + '.' + tabIndex,
|
||||||
|
view: {
|
||||||
|
render: (container) => {
|
||||||
|
this.initializeModelViewContainer(container, tab.content);
|
||||||
|
},
|
||||||
|
layout: (dimension) => { }
|
||||||
|
} as IPanelView
|
||||||
|
} as IPanelTab);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this._activeTabIndex = 0;
|
||||||
|
return this._body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap angular for the dialog's model view controller with the given model view ID
|
||||||
|
*/
|
||||||
|
private initializeModelViewContainer(bodyContainer: HTMLElement, modelViewId: string) {
|
||||||
|
this._bootstrapService.bootstrap(
|
||||||
|
DialogModule,
|
||||||
|
bodyContainer,
|
||||||
|
'dialog-modelview-container',
|
||||||
|
{ modelViewId: modelViewId } as DialogComponentParams,
|
||||||
|
undefined,
|
||||||
|
(moduleRef) => this._moduleRef = moduleRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
public show(): void {
|
||||||
|
this._body.classList.remove('dialogModal-hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide(): void {
|
||||||
|
this._body.classList.add('dialogModal-hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the theme registry on theme change to style the component
|
||||||
|
*/
|
||||||
|
public style(styles: IModalDialogStyles): void {
|
||||||
|
this._body.style.backgroundColor = styles.dialogBodyBackground ? styles.dialogBodyBackground.toString() : undefined;
|
||||||
|
this._body.style.color = styles.dialogForeground ? styles.dialogForeground.toString() : undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/sql/platform/dialog/dialogTypes.ts
Normal file
55
src/sql/platform/dialog/dialogTypes.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 sqlops from 'sqlops';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
export class DialogTab implements sqlops.window.modelviewdialog.DialogTab {
|
||||||
|
public content: string;
|
||||||
|
|
||||||
|
constructor(public title: string, content?: string) {
|
||||||
|
if (content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateContent(): void { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Dialog implements sqlops.window.modelviewdialog.Dialog {
|
||||||
|
public content: string | DialogTab[];
|
||||||
|
public okTitle: string;
|
||||||
|
public cancelTitle: string;
|
||||||
|
public customButtons: DialogButton[];
|
||||||
|
|
||||||
|
private _onOk: Emitter<void> = new Emitter<void>();
|
||||||
|
public readonly onOk: Event<void> = this._onOk.event;
|
||||||
|
private _onCancel: Emitter<void> = new Emitter<void>();
|
||||||
|
public readonly onCancel: Event<void> = this._onCancel.event;
|
||||||
|
|
||||||
|
constructor(public title: string, content?: string | DialogTab[]) {
|
||||||
|
if (content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public open(): void { }
|
||||||
|
public close(): void { }
|
||||||
|
public updateContent(): void { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DialogButton implements sqlops.window.modelviewdialog.Button {
|
||||||
|
public label: string;
|
||||||
|
public enabled: boolean;
|
||||||
|
private _onClick: Emitter<void> = new Emitter<void>();
|
||||||
|
public readonly onClick: Event<void> = this._onClick.event;
|
||||||
|
|
||||||
|
constructor(label: string, enabled: boolean) {
|
||||||
|
this.label = label;
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/sql/platform/dialog/media/dialogModal.css
Normal file
28
src/sql/platform/dialog/media/dialogModal.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.dialogModal-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 500px;
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal.wide .dialogModal-body {
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialogModal-pane {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialogModal-pane.dialogModal-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
112
src/sql/sqlops.proposed.d.ts
vendored
112
src/sql/sqlops.proposed.d.ts
vendored
@@ -203,4 +203,116 @@ declare module 'sqlops' {
|
|||||||
*/
|
*/
|
||||||
export function registerModelViewProvider(widgetId: string, handler: (view: ModelView) => void): void;
|
export function registerModelViewProvider(widgetId: string, handler: (view: ModelView) => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace window {
|
||||||
|
export namespace modelviewdialog {
|
||||||
|
/**
|
||||||
|
* Create a dialog with the given title
|
||||||
|
* @param title The title of the dialog, displayed at the top
|
||||||
|
*/
|
||||||
|
export function createDialog(title: string): Dialog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a dialog tab which can be included as part of the content of a dialog
|
||||||
|
* @param title The title of the page, displayed on the tab to select the page
|
||||||
|
*/
|
||||||
|
export function createTab(title: string): DialogTab;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a button which can be included in a dialog
|
||||||
|
* @param label The label of the button
|
||||||
|
*/
|
||||||
|
export function createButton(label: string): Button;
|
||||||
|
|
||||||
|
// Model view dialog classes
|
||||||
|
export interface Dialog {
|
||||||
|
/**
|
||||||
|
* The title of the dialog
|
||||||
|
*/
|
||||||
|
title: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content of the dialog. If multiple tabs are given they will be displayed with tabs
|
||||||
|
* If a string is given, it should be the ID of the dialog's model view content
|
||||||
|
* TODO mairvine 4/18/18: use a model view content type
|
||||||
|
*/
|
||||||
|
content: string | DialogTab[],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The caption of the OK button
|
||||||
|
*/
|
||||||
|
okTitle: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The caption of the Cancel button
|
||||||
|
*/
|
||||||
|
cancelTitle: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any additional buttons that should be displayed
|
||||||
|
*/
|
||||||
|
customButtons: Button[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the dialog
|
||||||
|
*/
|
||||||
|
open(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the dialog
|
||||||
|
*/
|
||||||
|
close(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialog on screen to reflect changes to the buttons or content
|
||||||
|
*/
|
||||||
|
updateContent(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when dialog's ok button is pressed
|
||||||
|
*/
|
||||||
|
readonly onOk: vscode.Event<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when dialog is canceled
|
||||||
|
*/
|
||||||
|
readonly onCancel: vscode.Event<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DialogTab {
|
||||||
|
/**
|
||||||
|
* The title of the tab
|
||||||
|
*/
|
||||||
|
title: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string giving the ID of the tab's model view content
|
||||||
|
* TODO mairvine 4/18/18: use a model view content type
|
||||||
|
*/
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dialog on screen to reflect changes to the content
|
||||||
|
*/
|
||||||
|
updateContent(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Button {
|
||||||
|
/**
|
||||||
|
* The label displayed on the button
|
||||||
|
*/
|
||||||
|
label: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the button is enabled
|
||||||
|
*/
|
||||||
|
enabled: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when the button is clicked
|
||||||
|
*/
|
||||||
|
readonly onClick: vscode.Event<void>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,10 +280,19 @@ export function createApiFactory(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const modelViewDialog: typeof sqlops.window.modelviewdialog = {
|
||||||
|
// TODO mairvine 4/18/18: Implement the extension layer for custom dialogs
|
||||||
|
createDialog(title: string): sqlops.window.modelviewdialog.Dialog { return undefined; },
|
||||||
|
createTab(title: string): sqlops.window.modelviewdialog.DialogTab { return undefined; },
|
||||||
|
createButton(label: string): sqlops.window.modelviewdialog.Button { return undefined; }
|
||||||
|
};
|
||||||
|
|
||||||
const window: typeof sqlops.window = {
|
const window: typeof sqlops.window = {
|
||||||
createDialog(name: string) {
|
createDialog(name: string) {
|
||||||
return extHostModalDialogs.createDialog(name);
|
return extHostModalDialogs.createDialog(name);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
modelviewdialog: modelViewDialog
|
||||||
};
|
};
|
||||||
|
|
||||||
const tasks: typeof sqlops.tasks = {
|
const tasks: typeof sqlops.tasks = {
|
||||||
|
|||||||
79
src/sqltest/platform/dialog/dialogPane.test.ts
Normal file
79
src/sqltest/platform/dialog/dialogPane.test.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Dialog, DialogTab } from 'sql/platform/dialog/dialogTypes';
|
||||||
|
import { Mock, It, Times } from 'typemoq';
|
||||||
|
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||||
|
import { DialogComponentParams } from 'sql/platform/dialog/dialogContainer.component';
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
suite('Dialog Pane Tests', () => {
|
||||||
|
let dialog: Dialog;
|
||||||
|
let mockBootstrapService: Mock<IBootstrapService>;
|
||||||
|
let container: HTMLElement;
|
||||||
|
|
||||||
|
setup(() => {
|
||||||
|
dialog = new Dialog('test_dialog');
|
||||||
|
mockBootstrapService = Mock.ofInstance({
|
||||||
|
bootstrap: () => undefined
|
||||||
|
} as any);
|
||||||
|
mockBootstrapService.setup(x => x.bootstrap(It.isAny(), It.isAny(), It.isAny(), It.isAny(), undefined, It.isAny()));
|
||||||
|
container = document.createElement('div');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Creating a pane from content without tabs initializes the model view content correctly', () => {
|
||||||
|
// If I fill in a dialog's content with the ID of a specific model view provider and then render the dialog
|
||||||
|
let modelViewId = 'test_content';
|
||||||
|
dialog.content = modelViewId;
|
||||||
|
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||||
|
dialogPane.createBody(container);
|
||||||
|
|
||||||
|
// Then a single dialog-modelview-container element is added directly to the dialog pane
|
||||||
|
mockBootstrapService.verify(x => x.bootstrap(
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.is((x: DialogComponentParams) => x.modelViewId === modelViewId),
|
||||||
|
undefined,
|
||||||
|
It.isAny()), Times.once());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Creating a pane from content with a single tab initializes without showing tabs', () => {
|
||||||
|
// If I fill in a dialog's content with a single tab and then render the dialog
|
||||||
|
let modelViewId = 'test_content';
|
||||||
|
dialog.content = [new DialogTab('', modelViewId)];
|
||||||
|
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||||
|
dialogPane.createBody(container);
|
||||||
|
|
||||||
|
// Then a single dialog-modelview-container element is added directly to the dialog pane
|
||||||
|
mockBootstrapService.verify(x => x.bootstrap(
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.is((x: DialogComponentParams) => x.modelViewId === modelViewId),
|
||||||
|
undefined,
|
||||||
|
It.isAny()), Times.once());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Creating a pane from content with multiple tabs initializes multiple model view tabs', () => {
|
||||||
|
// If I fill in a dialog's content with a single tab and then render the dialog
|
||||||
|
let modelViewId1 = 'test_content_1';
|
||||||
|
let modelViewId2 = 'test_content_2';
|
||||||
|
dialog.content = [new DialogTab('tab1', modelViewId1), new DialogTab('tab2', modelViewId2)];
|
||||||
|
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||||
|
dialogPane.createBody(container);
|
||||||
|
|
||||||
|
// Then a dialog-modelview-container element is added for the first tab (subsequent ones get added when the tab is actually clicked)
|
||||||
|
mockBootstrapService.verify(x => x.bootstrap(
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.isAny(),
|
||||||
|
It.is((x: DialogComponentParams) => x.modelViewId === modelViewId1),
|
||||||
|
undefined,
|
||||||
|
It.isAny()), Times.once());
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user