SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,271 @@
/*---------------------------------------------------------------------------------------------
* 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 { Disposable } from 'vs/base/common/lifecycle';
import { Dimension } from 'vs/base/browser/builder';
import Event, { Emitter } from 'vs/base/common/event';
import { IHorizontalSashLayoutProvider, IVerticalSashLayoutProvider,
ISashEvent, Orientation, VSash, Sash } from 'vs/base/browser/ui/sash/sash';
// There is no need to import the sash CSS - 'vs/base/browser/ui/sash/sash' already includes it
/**
* Interface describing a sash that could be horizontal or vertical. This interface allows classes
* using the sash to have UI logic that is agnostic of the orientation of the sash.
*/
export interface IFlexibleSash {
// Get the value of the CSS property denoted by getMajorPosition()
getSplitPoint(): number;
// Sets the Dimension containing the height and width of the editor this sash will separate
setDimenesion(dimension: Dimension);
// Re-calculates the width and height of the sash
layout(): void;
// Hides the sash
hide(): void;
// Shows/unhides the sash
show(): void;
// Sets the top or left property of this sash
setEdge(edge: number);
// Fired when the position of this sash changes
onPositionChange: Event<number>;
}
/**
* A simple Vertical Sash that computes the position of the sash when it is moved between the given dimension.
* Triggers onPositionChange event when the position is changed. Implements IFlexibleSash to enable classes to be
* agnostic of the fact that this sash is vertical.
*/
export class VerticalFlexibleSash extends Disposable implements IVerticalSashLayoutProvider, IFlexibleSash {
private sash: Sash;
private ratio: number;
private startPosition: number;
private position: number;
private dimension: Dimension;
private top: number;
private _onPositionChange: Emitter<number> = new Emitter<number>();
public get onPositionChange(): Event<number> { return this._onPositionChange.event; }
constructor(container: HTMLElement, private minWidth: number) {
super();
this.ratio = 0.5;
this.top = 0;
this.sash = new Sash(container, this);
this._register(this.sash.addListener('start', () => this.onSashDragStart()));
this._register(this.sash.addListener('change', (e: ISashEvent) => this.onSashDrag(e)));
this._register(this.sash.addListener('end', () => this.onSashDragEnd()));
this._register(this.sash.addListener('reset', () => this.onSashReset()));
}
public getSplitPoint(): number {
return this.getVerticalSashLeft();
}
public layout(): void {
this.sash.layout();
}
public show(): void {
this.sash.show();
}
public hide(): void {
this.sash.hide();
}
public getVerticalSashTop(): number {
return this.top;
}
public getVerticalSashLeft(): number {
return this.position;
}
public getVerticalSashHeight(): number {
return this.dimension.height;
}
public setDimenesion(dimension: Dimension) {
this.dimension = dimension;
this.compute(this.ratio);
}
public setEdge(edge: number) {
this.top = edge;
}
private onSashDragStart(): void {
this.startPosition = this.position;
}
private onSashDrag(e: ISashEvent): void {
this.compute((this.startPosition + (e.currentX - e.startX)) / this.dimension.width);
}
private compute(ratio: number) {
this.computeSashPosition(ratio);
this.ratio = this.position / this.dimension.width;
this._onPositionChange.fire(this.position);
}
private onSashDragEnd(): void {
this.sash.layout();
}
private onSashReset(): void {
this.ratio = 0.5;
this._onPositionChange.fire(this.position);
this.sash.layout();
}
private computeSashPosition(sashRatio: number = this.ratio) {
let contentWidth = this.dimension.width;
let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth);
let midPoint = Math.floor(0.5 * contentWidth);
if (contentWidth > this.minWidth * 2) {
if (sashPosition < this.minWidth) {
sashPosition = this.minWidth;
}
if (sashPosition > contentWidth - this.minWidth) {
sashPosition = contentWidth - this.minWidth;
}
} else {
sashPosition = midPoint;
}
if (this.position !== sashPosition) {
this.position = sashPosition;
this.sash.layout();
}
}
}
/**
* A simple Horizontal Sash that computes the position of the sash when it is moved between the given dimension.
* Triggers onPositionChange event when the position is changed. Implements IFlexibleSash to enable classes to be
* agnostic of the fact that this sash is horizontal. Based off the VSash class.
*/
export class HorizontalFlexibleSash extends Disposable implements IHorizontalSashLayoutProvider, IFlexibleSash {
private sash: Sash;
private ratio: number;
private startPosition: number;
private position: number;
private dimension: Dimension;
private left: number;
private _onPositionChange: Emitter<number> = new Emitter<number>();
public get onPositionChange(): Event<number> { return this._onPositionChange.event; }
constructor(container: HTMLElement, private minHeight: number) {
super();
this.ratio = 0.5;
this.left = 0;
this.sash = new Sash(container, this, { orientation: Orientation.HORIZONTAL });
this._register(this.sash.addListener('start', () => this.onSashDragStart()));
this._register(this.sash.addListener('change', (e: ISashEvent) => this.onSashDrag(e)));
this._register(this.sash.addListener('end', () => this.onSashDragEnd()));
this._register(this.sash.addListener('reset', () => this.onSashReset()));
}
public getSplitPoint(): number {
return this.getHorizontalSashTop();
}
public getHorizontalSashLeft(): number {
return this.left;
}
public getHorizontalSashTop(): number {
return this.position;
}
public layout(): void {
this.sash.layout();
}
public show(): void {
this.sash.show();
}
public hide(): void {
this.sash.hide();
}
public getHorizontalSashWidth?(): number {
return this.dimension.width;
}
public setDimenesion(dimension: Dimension) {
this.dimension = dimension;
this.compute(this.ratio);
}
public setEdge(edge: number) {
this.left = edge;
}
private onSashDragStart(): void {
this.startPosition = this.position;
}
private onSashDrag(e: ISashEvent): void {
this.compute((this.startPosition + (e.currentY - e.startY)) / this.dimension.height);
}
private compute(ratio: number) {
this.computeSashPosition(ratio);
this.ratio = this.position / this.dimension.height;
this._onPositionChange.fire(this.position);
}
private onSashDragEnd(): void {
this.sash.layout();
}
private onSashReset(): void {
this.ratio = 0.5;
this._onPositionChange.fire(this.position);
this.sash.layout();
}
/**
* Computes where the sash should be located and re-renders the sash.
*/
private computeSashPosition(sashRatio: number = this.ratio) {
let contentHeight = this.dimension.height;
let sashPosition = Math.floor((sashRatio || 0.5) * contentHeight);
let midPoint = Math.floor(0.5 * contentHeight);
if (contentHeight > this.minHeight * 2) {
if (sashPosition < this.minHeight) {
sashPosition = this.minHeight;
}
if (sashPosition > contentHeight - this.minHeight) {
sashPosition = contentHeight - this.minHeight;
}
} else {
sashPosition = midPoint;
}
if (this.position !== sashPosition) {
this.position = sashPosition;
this.sash.layout();
}
}
}

View File

@@ -0,0 +1,33 @@
<!--
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<panel class="fullsize" [options]="panelOpt">
<tab [title]="queryComponentTitle" class="fullsize" [identifier]="resultsTabIdentifier">
<div id="queryDiv" class="fullsize">
<query-component id="queryComp" #queryComponent class="fullsize" [queryParameters]="queryParameters"></query-component>
</div>
</tab>
<tab *ngIf="hasQueryPlan" [title]="queryPlanTitle" [identifier]="queryPlanTabIdentifier">
<div id="queryPlanDiv" class="headersVisible fullsize" style=" overflow: auto; margin-left: 2px">
<queryplan-component #queryPlanComponent class="fullsize" style="display: block"></queryplan-component>
</div>
</tab>
<tab *ngIf="hasQueryPlan" class="fullsize" [title]="topOperationsTitle">
<div id="topOperationsDiv" class="fullsize">
<top-operations-component #topOperationsComponent class="fullsize" style="display: block" [queryParameters]="queryParameters"></top-operations-component>
</div>
</tab>
<tab *ngIf="showChartView" [title]="chartViewerTitle" [identifier]="chartViewerTabIdentifier">
<div id="chartViewerDiv" class="headersVisible fullsize" >
<chart-viewer #chartViewerComponent class="fullsize" style="display: block">
</chart-viewer>
</div>
</tab>
</panel>

View File

@@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* 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/parts/grid/media/slickColorTheme';
import 'vs/css!sql/parts/grid/media/flexbox';
import 'vs/css!sql/parts/grid/media/styles';
import 'vs/css!sql/parts/grid/media/slick.grid';
import 'vs/css!sql/parts/grid/media/slickGrid';
import { ElementRef, ChangeDetectorRef, OnInit, OnDestroy, Component, Inject, forwardRef, ViewChild } from '@angular/core';
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { QueryComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { QueryComponent } from 'sql/parts/grid/views/query/query.component';
import { QueryPlanComponent } from 'sql/parts/queryPlan/queryPlan.component';
import { TopOperationsComponent } from 'sql/parts/queryPlan/topOperations.component';
import { ChartViewerComponent } from 'sql/parts/grid/views/query/chartViewer.component';
import { toDisposableSubscription } from 'sql/parts/common/rxjsUtils';
import { PanelComponent, IPanelOptions } from 'sql/base/browser/ui/panel/panel.component';
import * as nls from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
export const QUERY_OUTPUT_SELECTOR: string = 'query-output-component';
declare type PaneType = 'messages' | 'results';
@Component({
selector: QUERY_OUTPUT_SELECTOR,
templateUrl: decodeURI(require.toUrl('sql/parts/query/views/queryOutput.component.html'))
})
export class QueryOutputComponent implements OnInit, OnDestroy {
@ViewChild('queryComponent') queryComponent: QueryComponent;
@ViewChild('queryPlanComponent') queryPlanComponent: QueryPlanComponent;
@ViewChild('topOperationsComponent') topOperationsComponent: TopOperationsComponent;
@ViewChild('chartViewerComponent') chartViewerComponent: ChartViewerComponent;
@ViewChild(PanelComponent) private _panel: PanelComponent;
// tslint:disable:no-unused-variable
private readonly queryComponentTitle: string = nls.localize('results', 'Results');
private readonly queryPlanTitle: string = nls.localize('queryPlan', 'Query Plan');
private readonly topOperationsTitle: string = nls.localize('topOperations', 'Top Operations');
private readonly chartViewerTitle: string = nls.localize('chartViewer', 'Chart Viewer');
private readonly resultsTabIdentifier = 'results';
private readonly queryPlanTabIdentifier = 'queryPlan';
private readonly chartViewerTabIdentifier = 'chartViewer';
// tslint:enable:no-unused-variable
private hasQueryPlan = false;
private showChartView = false;
// tslint:disable-next-line:no-unused-variable
private readonly panelOpt: IPanelOptions = {
showTabsWhenOne: false
};
public queryParameters: QueryComponentParams;
private _disposables: Array<IDisposable> = [];
constructor(
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(BOOTSTRAP_SERVICE_ID) bootstrapService: IBootstrapService
) {
this.queryParameters = bootstrapService.getBootstrapParams(el.nativeElement.tagName);
}
/**
* Called by Angular when the object is initialized
*/
public ngOnInit(): void {
this._disposables.push(toDisposableSubscription(this.queryComponent.queryPlanAvailable.subscribe((xml) => {
this.hasQueryPlan = true;
this._cd.detectChanges();
this._panel.selectTab(this.queryPlanTabIdentifier);
this.queryPlanComponent.planXml = xml;
this.topOperationsComponent.planXml = xml;
})));
this._disposables.push(toDisposableSubscription(this.queryComponent.showChartRequested.subscribe((dataSet) => {
this.showChartView = true;
this._cd.detectChanges();
this.chartViewerComponent.dataSet = dataSet;
this._panel.selectTab(this.chartViewerTabIdentifier);
})));
this._disposables.push(toDisposableSubscription(this.queryComponent.queryExecutionStatus.subscribe(status => {
if (status === 'start') {
this._panel.selectTab(this.resultsTabIdentifier);
this.hasQueryPlan = false;
this.showChartView = false;
this._cd.detectChanges();
}
})));
}
public ngOnDestroy(): void {
this._disposables.forEach(i => i.dispose());
}
}

View File

@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ApplicationRef, ComponentFactoryResolver, forwardRef, NgModule, Inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { SlickGrid } from 'angular2-slickgrid';
import { ChartsModule } from 'ng2-charts/ng2-charts';
const BrowserAnimationsModule = (<any>require.__$__nodeRequire('@angular/platform-browser/animations')).BrowserAnimationsModule;
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { QueryOutputComponent, QUERY_OUTPUT_SELECTOR } from 'sql/parts/query/views/queryOutput.component';
import { QueryPlanComponent, } from 'sql/parts/queryPlan/queryPlan.component';
import { QueryComponent } from 'sql/parts/grid/views/query/query.component';
import { TopOperationsComponent } from 'sql/parts/queryPlan/topOperations.component';
import { ChartViewerComponent } from 'sql/parts/grid/views/query/chartViewer.component';
import { PanelModule } from 'sql/base/browser/ui/panel/panel.module';
/* Directives */
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
import { MouseDownDirective } from 'sql/parts/grid/directives/mousedown.directive';
import { ScrollDirective } from 'sql/parts/grid/directives/scroll.directive';
let baseComponents = [QueryComponent, ComponentHostDirective, QueryOutputComponent, QueryPlanComponent, TopOperationsComponent, ChartViewerComponent];
/* Insights */
let insightComponents = Registry.as<IInsightRegistry>(Extensions.InsightContribution).getAllCtors();
@NgModule({
imports: [
CommonModule,
BrowserModule,
FormsModule,
BrowserAnimationsModule,
ChartsModule,
PanelModule
],
declarations: [
...baseComponents,
...insightComponents,
SlickGrid,
ScrollDirective,
MouseDownDirective
],
entryComponents: [
QueryOutputComponent,
...insightComponents
]
})
export class QueryOutputModule {
constructor(
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService
) {
}
ngDoBootstrap(appRef: ApplicationRef) {
const factory = this._resolver.resolveComponentFactory(QueryOutputComponent);
const uniqueSelector: string = this._bootstrapService.getUniqueSelector(QUERY_OUTPUT_SELECTOR);
(<any>factory).factory.selector = uniqueSelector;
appRef.bootstrap(factory);
}
}