mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 09:35:38 -05:00
Initial work for custom model view dialogs (#1183)
This commit is contained in:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user