diff --git a/src/sql/parts/dashboard/contents/webviewContent.component.ts b/src/sql/parts/dashboard/contents/webviewContent.component.ts new file mode 100644 index 0000000000..b9ce539996 --- /dev/null +++ b/src/sql/parts/dashboard/contents/webviewContent.component.ts @@ -0,0 +1,116 @@ +/*--------------------------------------------------------------------------------------------- +* Copyright (c) Microsoft Corporation. All rights reserved. +* Licensed under the Source EULA. See License.txt in the project root for license information. +*--------------------------------------------------------------------------------------------*/ +import 'vs/css!./webviewContent'; + +import { Component, forwardRef, Input, OnInit, Inject, ChangeDetectorRef, ElementRef } from '@angular/core'; + +import Event, { Emitter } from 'vs/base/common/event'; +import Webview from 'vs/workbench/parts/html/browser/webview'; +import { Parts } from 'vs/workbench/services/part/common/partService'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +import { DashboardTab } from 'sql/parts/dashboard/common/interfaces'; +import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget'; +import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; +import { IDashboardWebview } from 'sql/services/dashboardWebview/common/dashboardWebviewService'; + +import * as data from 'data'; +import { memoize } from 'vs/base/common/decorators'; + +@Component({ + template: '', + selector: 'webview-content' +}) +export class WebviewContent implements OnInit, IDashboardWebview { + @Input() private webviewId: string; + + private _onResize = new Emitter(); + public readonly onResize: Event = this._onResize.event; + private _onMessage = new Emitter(); + public readonly onMessage: Event = this._onMessage.event; + private _onMessageDisposable: IDisposable; + private _webview: Webview; + private _html: string; + + constructor( + @Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface, + @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, + @Inject(forwardRef(() => ElementRef)) private _el: ElementRef + ) { + } + + ngOnInit() { + this._dashboardService.dashboardWebviewService.registerWebview(this); + this._createWebview(); + } + + public layout(): void { + this._createWebview(); + } + + public get id(): string { + return this.webviewId; + } + + @memoize + public get connection(): data.connection.Connection { + let currentConnection = this._dashboardService.connectionManagementService.connectionInfo.connectionProfile; + let connection: data.connection.Connection = { + providerName: currentConnection.providerName, + connectionId: currentConnection.id, + options: currentConnection.options + }; + return connection; + } + + @memoize + public get serverInfo(): data.ServerInfo { + return this._dashboardService.connectionManagementService.connectionInfo.serverInfo; + } + + public setHtml(html: string): void { + this._html = html; + if (this._webview) { + this._webview.contents = [html]; + this._webview.layout(); + } + } + + public sendMessage(message: string): void { + if (this._webview) { + this._webview.sendMessage(message); + } + } + + private _createWebview(): void { + if (this._webview) { + this._webview.dispose(); + } + + if (this._onMessageDisposable) { + this._onMessageDisposable.dispose(); + } + + this._webview = new Webview(this._el.nativeElement, + this._dashboardService.partService.getContainer(Parts.EDITOR_PART), + this._dashboardService.contextViewService, + undefined, + undefined, + { + allowScripts: true, + enableWrappedPostMessage: true, + hideFind: true + } + ); + this._onMessageDisposable = this._webview.onMessage(e => { + this._onMessage.fire(e); + }); + this._webview.style(this._dashboardService.themeService.getTheme()); + if (this._html) { + this._webview.contents = [this._html]; + } + this._webview.layout(); + } +} diff --git a/src/sql/parts/dashboard/contents/webviewContent.css b/src/sql/parts/dashboard/contents/webviewContent.css new file mode 100644 index 0000000000..1763e033f4 --- /dev/null +++ b/src/sql/parts/dashboard/contents/webviewContent.css @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +webview-content { + height: 100%; + width : 100%; + display: block; +} diff --git a/src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.html b/src/sql/parts/dashboard/contents/widgetContent.component.html similarity index 100% rename from src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.html rename to src/sql/parts/dashboard/contents/widgetContent.component.html diff --git a/src/sql/parts/dashboard/contents/widgetContent.component.ts b/src/sql/parts/dashboard/contents/widgetContent.component.ts new file mode 100644 index 0000000000..2e5891b32d --- /dev/null +++ b/src/sql/parts/dashboard/contents/widgetContent.component.ts @@ -0,0 +1,203 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./widgetContent'; + +import { Component, Inject, Input, forwardRef, ViewChild, ViewChildren, QueryList, ChangeDetectorRef } from '@angular/core'; +import { NgGridConfig, NgGrid, NgGridItem } from 'angular2-grid'; + +import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; +import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget'; +import { DashboardWidgetWrapper } from 'sql/parts/dashboard/common/dashboardWidgetWrapper.component'; +import { subscriptionToDisposable } from 'sql/base/common/lifecycle'; + +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import * as objects from 'vs/base/common/objects'; +import Event, { Emitter } from 'vs/base/common/event'; + +/** + * Sorting function for dashboard widgets + * In order of priority; + * If neither have defined grid positions, they are equivalent + * If a has a defined grid position and b does not; a should come first + * If both have defined grid positions and have the same row; the one with the smaller col position should come first + * If both have defined grid positions but different rows (it doesn't really matter in this case) the lowers row should come first + */ +function configSorter(a, b): number { + if ((!a.gridItemConfig || !a.gridItemConfig.col) + && (!b.gridItemConfig || !b.gridItemConfig.col)) { + return 0; + } else if (!a.gridItemConfig || !a.gridItemConfig.col) { + return 1; + } else if (!b.gridItemConfig || !b.gridItemConfig.col) { + return -1; + } else if (a.gridItemConfig.row === b.gridItemConfig.row) { + if (a.gridItemConfig.col < b.gridItemConfig.col) { + return -1; + } + + if (a.gridItemConfig.col === b.gridItemConfig.col) { + return 0; + } + + if (a.gridItemConfig.col > b.gridItemConfig.col) { + return 1; + } + } else { + if (a.gridItemConfig.row < b.gridItemConfig.row) { + return -1; + } + + if (a.gridItemConfig.row === b.gridItemConfig.row) { + return 0; + } + + if (a.gridItemConfig.row > b.gridItemConfig.row) { + return 1; + } + } + + return void 0; // this should never be reached +} + +@Component({ + selector: 'widget-content', + templateUrl: decodeURI(require.toUrl('sql/parts/dashboard/contents/widgetContent.component.html')) +}) +export class WidgetContent { + @Input() private widgets: WidgetConfig[]; + @Input() private originalConfig: WidgetConfig[]; + @Input() private context: string; + private _onResize = new Emitter(); + public readonly onResize: Event = this._onResize.event; + + protected SKELETON_WIDTH = 5; + protected gridConfig: NgGridConfig = { + 'margins': [10], // The size of the margins of each item. Supports up to four values in the same way as CSS margins. Can be updated using setMargins() + 'draggable': false, // Whether the items can be dragged. Can be updated using enableDrag()/disableDrag() + 'resizable': false, // Whether the items can be resized. Can be updated using enableResize()/disableResize() + 'max_cols': this.SKELETON_WIDTH, // The maximum number of columns allowed. Set to 0 for infinite. Cannot be used with max_rows + 'max_rows': 0, // The maximum number of rows allowed. Set to 0 for infinite. Cannot be used with max_cols + 'visible_cols': 0, // The number of columns shown on screen when auto_resize is set to true. Set to 0 to not auto_resize. Will be overriden by max_cols + 'visible_rows': 0, // The number of rows shown on screen when auto_resize is set to true. Set to 0 to not auto_resize. Will be overriden by max_rows + 'min_cols': 0, // The minimum number of columns allowed. Can be any number greater than or equal to 1. + 'min_rows': 0, // The minimum number of rows allowed. Can be any number greater than or equal to 1. + 'col_width': 250, // The width of each column + 'row_height': 250, // The height of each row + 'cascade': 'left', // The direction to cascade grid items ('up', 'right', 'down', 'left') + 'min_width': 100, // The minimum width of an item. If greater than col_width, this will update the value of min_cols + 'min_height': 100, // The minimum height of an item. If greater than row_height, this will update the value of min_rows + 'fix_to_grid': false, // Fix all item movements to the grid + 'auto_style': true, // Automatically add required element styles at run-time + 'auto_resize': false, // Automatically set col_width/row_height so that max_cols/max_rows fills the screen. Only has effect is max_cols or max_rows is set + 'maintain_ratio': false, // Attempts to maintain aspect ratio based on the colWidth/rowHeight values set in the config + 'prefer_new': false, // When adding new items, will use that items position ahead of existing items + 'limit_to_screen': true, // When resizing the screen, with this true and auto_resize false, the grid will re-arrange to fit the screen size. Please note, at present this only works with cascade direction up. + }; + + private _editDispose: Array = []; + + @ViewChild(NgGrid) private _grid: NgGrid; + @ViewChildren(DashboardWidgetWrapper) private _widgets: QueryList; + @ViewChildren(NgGridItem) private _items: QueryList; + constructor( + @Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface, + @Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef + ) { + } + + public layout() { + if (this._widgets) { + this._widgets.forEach(item => { + item.layout(); + }); + } + this._grid.triggerResize(); + } + + public refresh(): void { + if (this._widgets) { + this._widgets.forEach(item => { + item.refresh(); + }); + } + } + + public enableEdit(): void { + if (this._grid.dragEnable) { + this._grid.disableDrag(); + this._grid.disableResize(); + this._editDispose.forEach(i => i.dispose()); + this._widgets.forEach(i => { + if (i.id) { + i.disableEdit(); + } + }); + this._editDispose = []; + } else { + this._grid.enableResize(); + this._grid.enableDrag(); + this._editDispose.push(this.dashboardService.onDeleteWidget(e => { + let index = this.widgets.findIndex(i => i.id === e); + this.widgets.splice(index, 1); + + index = this.originalConfig.findIndex(i => i.id === e); + this.originalConfig.splice(index, 1); + + this._rewriteConfig(); + this._cd.detectChanges(); + })); + this._editDispose.push(subscriptionToDisposable(this._grid.onResizeStop.subscribe((e: NgGridItem) => { + this._onResize.fire(); + let event = e.getEventOutput(); + let config = this.originalConfig.find(i => i.id === event.payload.id); + + if (!config.gridItemConfig) { + config.gridItemConfig = {}; + } + config.gridItemConfig.sizex = e.sizex; + config.gridItemConfig.sizey = e.sizey; + + let component = this._widgets.find(i => i.id === event.payload.id); + + component.layout(); + this._rewriteConfig(); + }))); + this._editDispose.push(subscriptionToDisposable(this._grid.onDragStop.subscribe((e: NgGridItem) => { + this._onResize.fire(); + let event = e.getEventOutput(); + this._items.forEach(i => { + let config = this.originalConfig.find(j => j.id === i.getEventOutput().payload.id); + if ((config.gridItemConfig && config.gridItemConfig.col) || config.id === event.payload.id) { + if (!config.gridItemConfig) { + config.gridItemConfig = {}; + } + config.gridItemConfig.col = i.col; + config.gridItemConfig.row = i.row; + } + }); + this.originalConfig.sort(configSorter); + + this._rewriteConfig(); + }))); + this._widgets.forEach(i => { + if (i.id) { + i.enableEdit(); + } + }); + } + } + + private _rewriteConfig(): void { + let writeableConfig = objects.deepClone(this.originalConfig); + + writeableConfig.forEach(i => { + delete i.id; + }); + let target: ConfigurationTarget = ConfigurationTarget.USER; + this.dashboardService.writeSettings([this.context, 'widgets'].join('.'), writeableConfig, target); + } +} diff --git a/src/sql/parts/dashboard/contents/widgetContent.css b/src/sql/parts/dashboard/contents/widgetContent.css new file mode 100644 index 0000000000..7ceb52837f --- /dev/null +++ b/src/sql/parts/dashboard/contents/widgetContent.css @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +widget-content { + height: 100%; + width: 100%; +} \ No newline at end of file diff --git a/src/sql/parts/dashboard/dashboard.module.ts b/src/sql/parts/dashboard/dashboard.module.ts index 302e4747d1..f01373543a 100644 --- a/src/sql/parts/dashboard/dashboard.module.ts +++ b/src/sql/parts/dashboard/dashboard.module.ts @@ -29,9 +29,11 @@ import { DashboardComponent, DASHBOARD_SELECTOR } from 'sql/parts/dashboard/dash import { DashboardWidgetWrapper } from 'sql/parts/dashboard/common/dashboardWidgetWrapper.component'; import { DashboardWidgetTab } from 'sql/parts/dashboard/tabs/dashboardWidgetTab.component'; import { DashboardWebviewTab } from 'sql/parts/dashboard/tabs/dashboardWebviewTab.component'; +import { WidgetContent } from 'sql/parts/dashboard/contents/widgetContent.component'; +import { WebviewContent } from 'sql/parts/dashboard/contents/webviewContent.component'; import { BreadcrumbComponent } from 'sql/base/browser/ui/breadcrumb/breadcrumb.component'; import { IBreadcrumbService } from 'sql/base/browser/ui/breadcrumb/interfaces'; -let baseComponents = [DashboardComponent, DashboardWidgetWrapper, DashboardWebviewTab, DashboardWidgetTab, ComponentHostDirective, BreadcrumbComponent]; +let baseComponents = [DashboardComponent, DashboardWidgetWrapper, DashboardWebviewTab, DashboardWidgetTab, WidgetContent, WebviewContent, ComponentHostDirective, BreadcrumbComponent]; /* Panel */ import { PanelModule } from 'sql/base/browser/ui/panel/panel.module'; diff --git a/src/sql/parts/dashboard/tabs/dashboardWebviewTab.component.ts b/src/sql/parts/dashboard/tabs/dashboardWebviewTab.component.ts index 065e0e474d..4c28fcabc2 100644 --- a/src/sql/parts/dashboard/tabs/dashboardWebviewTab.component.ts +++ b/src/sql/parts/dashboard/tabs/dashboardWebviewTab.component.ts @@ -4,52 +4,41 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./dashboardWebviewTab'; -import { Component, forwardRef, Input, OnInit, Inject, ChangeDetectorRef, ElementRef } from '@angular/core'; +import { Component, forwardRef, Input, AfterContentInit, ViewChild } from '@angular/core'; import Event, { Emitter } from 'vs/base/common/event'; -import Webview from 'vs/workbench/parts/html/browser/webview'; -import { Parts } from 'vs/workbench/services/part/common/partService'; -import { IDisposable } from 'vs/base/common/lifecycle'; import { DashboardTab } from 'sql/parts/dashboard/common/interfaces'; import { TabConfig } from 'sql/parts/dashboard/common/dashboardWidget'; -import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; -import { IDashboardWebview } from 'sql/services/dashboardWebview/common/dashboardWebviewService'; - -import * as data from 'data'; -import { memoize } from 'vs/base/common/decorators'; +import { WebviewContent } from 'sql/parts/dashboard/contents/webviewContent.component'; @Component({ - template: '', selector: 'dashboard-webview-tab', - providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardWebviewTab) }] + providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardWebviewTab) }], + template: ` + + + ` }) -export class DashboardWebviewTab extends DashboardTab implements OnInit, IDashboardWebview { +export class DashboardWebviewTab extends DashboardTab implements AfterContentInit { @Input() private tab: TabConfig; private _onResize = new Emitter(); public readonly onResize: Event = this._onResize.event; - private _onMessage = new Emitter(); - public readonly onMessage: Event = this._onMessage.event; - private _onMessageDisposable: IDisposable; - private _webview: Webview; - private _html: string; - constructor( - @Inject(forwardRef(() => DashboardServiceInterface)) private _dashboardService: DashboardServiceInterface, - @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, - @Inject(forwardRef(() => ElementRef)) private _el: ElementRef - ) { + @ViewChild(WebviewContent) private _webviewContent: WebviewContent; + constructor() { super(); } - ngOnInit() { - this._dashboardService.dashboardWebviewService.registerWebview(this); - this._createWebview(); + ngAfterContentInit(): void { + this._register(this._webviewContent.onResize(() => { + this._onResize.fire(); + })); } public layout(): void { - this._createWebview(); + this._webviewContent.layout(); } public get id(): string { @@ -60,67 +49,7 @@ export class DashboardWebviewTab extends DashboardTab implements OnInit, IDashbo return this.tab.editable; } - @memoize - public get connection(): data.connection.Connection { - let currentConnection = this._dashboardService.connectionManagementService.connectionInfo.connectionProfile; - let connection: data.connection.Connection = { - providerName: currentConnection.providerName, - connectionId: currentConnection.id, - options: currentConnection.options - }; - return connection; - } - - @memoize - public get serverInfo(): data.ServerInfo { - return this._dashboardService.connectionManagementService.connectionInfo.serverInfo; - } - public refresh(): void { // no op } - - public setHtml(html: string): void { - this._html = html; - if (this._webview) { - this._webview.contents = [html]; - this._webview.layout(); - } - } - - public sendMessage(message: string): void { - if (this._webview) { - this._webview.sendMessage(message); - } - } - - private _createWebview(): void { - if (this._webview) { - this._webview.dispose(); - } - - if (this._onMessageDisposable) { - this._onMessageDisposable.dispose(); - } - - this._webview = new Webview(this._el.nativeElement, - this._dashboardService.partService.getContainer(Parts.EDITOR_PART), - this._dashboardService.contextViewService, - undefined, - undefined, - { - allowScripts: true, - enableWrappedPostMessage: true, - hideFind: true - } - ); - this._onMessageDisposable = this._webview.onMessage(e => { - this._onMessage.fire(e); - }); - this._webview.style(this._dashboardService.themeService.getTheme()); - if (this._html) { - this._webview.contents = [this._html]; - } - this._webview.layout(); - } } diff --git a/src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.ts b/src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.ts index 69e4e2cf94..9c9ffed83a 100644 --- a/src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.ts +++ b/src/sql/parts/dashboard/tabs/dashboardWidgetTab.component.ts @@ -5,7 +5,7 @@ import 'vs/css!./dashboardWidgetTab'; -import { Component, Inject, Input, forwardRef, ViewChild, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef, EventEmitter, OnChanges } from '@angular/core'; +import { Component, Inject, Input, forwardRef, ViewChild, ElementRef, ViewChildren, QueryList, OnDestroy, ChangeDetectorRef, EventEmitter, OnChanges, AfterContentInit } from '@angular/core'; import { NgGridConfig, NgGrid, NgGridItem } from 'angular2-grid'; import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service'; @@ -13,108 +13,34 @@ import { TabConfig, WidgetConfig } from 'sql/parts/dashboard/common/dashboardWid import { DashboardWidgetWrapper } from 'sql/parts/dashboard/common/dashboardWidgetWrapper.component'; import { subscriptionToDisposable } from 'sql/base/common/lifecycle'; import { DashboardTab } from 'sql/parts/dashboard/common/interfaces'; +import { WidgetContent } from 'sql/parts/dashboard/contents/widgetContent.component'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import * as objects from 'vs/base/common/objects'; import Event, { Emitter } from 'vs/base/common/event'; -/** - * Sorting function for dashboard widgets - * In order of priority; - * If neither have defined grid positions, they are equivalent - * If a has a defined grid position and b does not; a should come first - * If both have defined grid positions and have the same row; the one with the smaller col position should come first - * If both have defined grid positions but different rows (it doesn't really matter in this case) the lowers row should come first - */ -function configSorter(a, b): number { - if ((!a.gridItemConfig || !a.gridItemConfig.col) - && (!b.gridItemConfig || !b.gridItemConfig.col)) { - return 0; - } else if (!a.gridItemConfig || !a.gridItemConfig.col) { - return 1; - } else if (!b.gridItemConfig || !b.gridItemConfig.col) { - return -1; - } else if (a.gridItemConfig.row === b.gridItemConfig.row) { - if (a.gridItemConfig.col < b.gridItemConfig.col) { - return -1; - } - - if (a.gridItemConfig.col === b.gridItemConfig.col) { - return 0; - } - - if (a.gridItemConfig.col > b.gridItemConfig.col) { - return 1; - } - } else { - if (a.gridItemConfig.row < b.gridItemConfig.row) { - return -1; - } - - if (a.gridItemConfig.row === b.gridItemConfig.row) { - return 0; - } - - if (a.gridItemConfig.row > b.gridItemConfig.row) { - return 1; - } - } - - return void 0; // this should never be reached -} - @Component({ selector: 'dashboard-widget-tab', - templateUrl: decodeURI(require.toUrl('sql/parts/dashboard/tabs/dashboardWidgetTab.component.html')), - providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardWidgetTab) }] + providers: [{ provide: DashboardTab, useExisting: forwardRef(() => DashboardWidgetTab) }], + template: ` + + + ` }) -export class DashboardWidgetTab extends DashboardTab implements OnDestroy, OnChanges { +export class DashboardWidgetTab extends DashboardTab implements OnDestroy, OnChanges, AfterContentInit { @Input() private tab: TabConfig; private widgets: WidgetConfig[]; private _onResize = new Emitter(); public readonly onResize: Event = this._onResize.event; - protected SKELETON_WIDTH = 5; - protected gridConfig: NgGridConfig = { - 'margins': [10], // The size of the margins of each item. Supports up to four values in the same way as CSS margins. Can be updated using setMargins() - 'draggable': false, // Whether the items can be dragged. Can be updated using enableDrag()/disableDrag() - 'resizable': false, // Whether the items can be resized. Can be updated using enableResize()/disableResize() - 'max_cols': this.SKELETON_WIDTH, // The maximum number of columns allowed. Set to 0 for infinite. Cannot be used with max_rows - 'max_rows': 0, // The maximum number of rows allowed. Set to 0 for infinite. Cannot be used with max_cols - 'visible_cols': 0, // The number of columns shown on screen when auto_resize is set to true. Set to 0 to not auto_resize. Will be overriden by max_cols - 'visible_rows': 0, // The number of rows shown on screen when auto_resize is set to true. Set to 0 to not auto_resize. Will be overriden by max_rows - 'min_cols': 0, // The minimum number of columns allowed. Can be any number greater than or equal to 1. - 'min_rows': 0, // The minimum number of rows allowed. Can be any number greater than or equal to 1. - 'col_width': 250, // The width of each column - 'row_height': 250, // The height of each row - 'cascade': 'left', // The direction to cascade grid items ('up', 'right', 'down', 'left') - 'min_width': 100, // The minimum width of an item. If greater than col_width, this will update the value of min_cols - 'min_height': 100, // The minimum height of an item. If greater than row_height, this will update the value of min_rows - 'fix_to_grid': false, // Fix all item movements to the grid - 'auto_style': true, // Automatically add required element styles at run-time - 'auto_resize': false, // Automatically set col_width/row_height so that max_cols/max_rows fills the screen. Only has effect is max_cols or max_rows is set - 'maintain_ratio': false, // Attempts to maintain aspect ratio based on the colWidth/rowHeight values set in the config - 'prefer_new': false, // When adding new items, will use that items position ahead of existing items - 'limit_to_screen': true, // When resizing the screen, with this true and auto_resize false, the grid will re-arrange to fit the screen size. Please note, at present this only works with cascade direction up. - }; - - private _editDispose: Array = []; - - @ViewChild(NgGrid) private _grid: NgGrid; - @ViewChildren(DashboardWidgetWrapper) private _widgets: QueryList; - @ViewChildren(NgGridItem) private _items: QueryList; + @ViewChild(WidgetContent) private _widgetContent: WidgetContent; constructor( - @Inject(forwardRef(() => DashboardServiceInterface)) protected dashboardService: DashboardServiceInterface, - @Inject(forwardRef(() => ElementRef)) protected _el: ElementRef, @Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef ) { super(); } - protected init() { - } - ngOnChanges() { if (this.tab.content) { this.widgets = Object.values(this.tab.content)[0]; @@ -122,6 +48,12 @@ export class DashboardWidgetTab extends DashboardTab implements OnDestroy, OnCha } } + ngAfterContentInit(): void { + this._register(this._widgetContent.onResize(() => { + this._onResize.fire(); + })); + } + ngOnDestroy() { this.dispose(); } @@ -135,94 +67,14 @@ export class DashboardWidgetTab extends DashboardTab implements OnDestroy, OnCha } public layout() { - if (this._widgets) { - this._widgets.forEach(item => { - item.layout(); - }); - } - this._grid.triggerResize(); + this._widgetContent.layout(); } public refresh(): void { - if (this._widgets) { - this._widgets.forEach(item => { - item.refresh(); - }); - } + this._widgetContent.layout(); } public enableEdit(): void { - if (this._grid.dragEnable) { - this._grid.disableDrag(); - this._grid.disableResize(); - this._editDispose.forEach(i => i.dispose()); - this._widgets.forEach(i => { - if (i.id) { - i.disableEdit(); - } - }); - this._editDispose = []; - } else { - this._grid.enableResize(); - this._grid.enableDrag(); - this._editDispose.push(this.dashboardService.onDeleteWidget(e => { - let index = this.widgets.findIndex(i => i.id === e); - this.widgets.splice(index, 1); - - index = this.tab.originalConfig.findIndex(i => i.id === e); - this.tab.originalConfig.splice(index, 1); - - this._rewriteConfig(); - this._cd.detectChanges(); - })); - this._editDispose.push(subscriptionToDisposable(this._grid.onResizeStop.subscribe((e: NgGridItem) => { - this._onResize.fire(); - let event = e.getEventOutput(); - let config = this.tab.originalConfig.find(i => i.id === event.payload.id); - - if (!config.gridItemConfig) { - config.gridItemConfig = {}; - } - config.gridItemConfig.sizex = e.sizex; - config.gridItemConfig.sizey = e.sizey; - - let component = this._widgets.find(i => i.id === event.payload.id); - - component.layout(); - this._rewriteConfig(); - }))); - this._editDispose.push(subscriptionToDisposable(this._grid.onDragStop.subscribe((e: NgGridItem) => { - this._onResize.fire(); - let event = e.getEventOutput(); - this._items.forEach(i => { - let config = this.tab.originalConfig.find(j => j.id === i.getEventOutput().payload.id); - if ((config.gridItemConfig && config.gridItemConfig.col) || config.id === event.payload.id) { - if (!config.gridItemConfig) { - config.gridItemConfig = {}; - } - config.gridItemConfig.col = i.col; - config.gridItemConfig.row = i.row; - } - }); - this.tab.originalConfig.sort(configSorter); - - this._rewriteConfig(); - }))); - this._widgets.forEach(i => { - if (i.id) { - i.enableEdit(); - } - }); - } - } - - private _rewriteConfig(): void { - let writeableConfig = objects.deepClone(this.tab.originalConfig); - - writeableConfig.forEach(i => { - delete i.id; - }); - let target: ConfigurationTarget = ConfigurationTarget.USER; - this.dashboardService.writeSettings([this.tab.context, 'widgets'].join('.'), writeableConfig, target); + this._widgetContent.enableEdit(); } } diff --git a/src/sql/parts/dashboard/tabs/dashboardWidgetTab.css b/src/sql/parts/dashboard/tabs/dashboardWidgetTab.css index 6bde0682e1..e46ab8f01a 100644 --- a/src/sql/parts/dashboard/tabs/dashboardWidgetTab.css +++ b/src/sql/parts/dashboard/tabs/dashboardWidgetTab.css @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -dashboard-tab { +dashboard-widget-tab { height: 100%; width: 100%; } \ No newline at end of file