From 19a11ba94b265c36ee6ca8fbbfe63e98356385c8 Mon Sep 17 00:00:00 2001 From: Alan Ren Date: Mon, 6 Apr 2020 12:25:09 -0700 Subject: [PATCH] tasks widget updates (#9860) * fix toolbar and remove tasks widget * update refresh action * remove contribution * fix missing learn more menu item * Alanren/refresh widgets new (#9863) * refresh widgets * dashboard refresh * update --- .../dashboardGridContainer.component.ts | 6 +- .../dashboardHomeContainer.component.ts | 5 + .../dashboardWidgetWrapper.component.ts | 2 - .../browser/core/dashboardPage.component.ts | 115 +++++------ .../dashboard/browser/core/dashboardWidget.ts | 17 +- .../dashboard/browser/dashboard.module.ts | 2 - .../explorer/explorerWidget.component.html | 7 +- .../explorer/explorerWidget.component.ts | 21 +-- .../insights/insightsWidget.component.ts | 45 +++-- .../propertiesWidget.component.html | 4 +- .../properties/propertiesWidget.component.ts | 16 +- .../widgets/tasks/media/taskWidget.css | 32 ---- .../widgets/tasks/tasksWidget.component.html | 8 - .../widgets/tasks/tasksWidget.component.ts | 178 ------------------ .../widgets/tasks/tasksWidget.contribution.ts | 38 ---- .../webview/webviewWidget.component.ts | 7 +- src/vs/workbench/workbench.common.main.ts | 1 - 17 files changed, 131 insertions(+), 373 deletions(-) delete mode 100644 src/sql/workbench/contrib/dashboard/browser/widgets/tasks/media/taskWidget.css delete mode 100644 src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.html delete mode 100644 src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.ts delete mode 100644 src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.contribution.ts diff --git a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.component.ts b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.component.ts index fae4fe5f49..df8429e785 100644 --- a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardGridContainer.component.ts @@ -235,8 +235,10 @@ export class DashboardGridContainer extends DashboardTab implements OnDestroy { widget.rowspan = '1'; } }); - this.rows = this.createIndexes(this._contents.map(w => w.row)); - this.cols = this.createIndexes(this._contents.map(w => w.col)); + if (this._contents.length > 0) { + this.rows = this.createIndexes(this._contents.map(w => w.row)); + this.cols = this.createIndexes(this._contents.map(w => w.col)); + } } } diff --git a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardHomeContainer.component.ts b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardHomeContainer.component.ts index 58626bd098..c4b4df0fa0 100644 --- a/src/sql/workbench/contrib/dashboard/browser/containers/dashboardHomeContainer.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/containers/dashboardHomeContainer.component.ts @@ -69,4 +69,9 @@ export class DashboardHomeContainer extends DashboardWidgetContainer { this._scrollable.layout(); } } + + public refresh(): void { + super.refresh(); + this._propertiesClass.refresh(); + } } diff --git a/src/sql/workbench/contrib/dashboard/browser/contents/dashboardWidgetWrapper.component.ts b/src/sql/workbench/contrib/dashboard/browser/contents/dashboardWidgetWrapper.component.ts index 459d4f465e..7a5931c2f9 100644 --- a/src/sql/workbench/contrib/dashboard/browser/contents/dashboardWidgetWrapper.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/contents/dashboardWidgetWrapper.component.ts @@ -20,7 +20,6 @@ import { AngularDisposable } from 'sql/base/browser/lifecycle'; /* Widgets */ import { PropertiesWidgetComponent } from 'sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component'; import { ExplorerWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component'; -import { TasksWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component'; import { InsightsWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component'; import { WebviewWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component'; @@ -42,7 +41,6 @@ import { IColorTheme } from 'vs/platform/theme/common/themeService'; const componentMap: { [x: string]: Type } = { 'properties-widget': PropertiesWidgetComponent, 'explorer-widget': ExplorerWidget, - 'tasks-widget': TasksWidget, 'insights-widget': InsightsWidget, 'webview-widget': WebviewWidget }; diff --git a/src/sql/workbench/contrib/dashboard/browser/core/dashboardPage.component.ts b/src/sql/workbench/contrib/dashboard/browser/core/dashboardPage.component.ts index ab906ad2d4..e29bb595b8 100644 --- a/src/sql/workbench/contrib/dashboard/browser/core/dashboardPage.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/core/dashboardPage.component.ts @@ -82,7 +82,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig // tslint:disable:no-unused-variable private readonly homeTabTitle: string = nls.localize('home', "Home"); private readonly homeTabId: string = 'homeTab'; - private tabToolbarActionsConfig = new Map(); + private tabToolbarActionsConfig = new Map(); private tabContents = new Map(); static tabName = new RawContextKey('tabName', undefined); @@ -145,12 +145,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig }); } else { let tempWidgets = this.dashboardService.getSettings>([this.context, 'widgets'].join('.')); - // remove tasks widget because those will be shown in the toolbar - const index = tempWidgets.findIndex(c => c.widget['tasks-widget']); - if (index !== -1) { - tempWidgets.splice(index, 1); - } - + this.processTasksWidgets(tempWidgets, this.homeTabId); this._originalConfig = objects.deepClone(tempWidgets); let properties = this.getProperties(); this._configModifiers.forEach((cb) => { @@ -170,8 +165,6 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig } this.showToolbar = true; - const homeToolbarConfig = this.dashboardService.getSettings>([this.context, 'widgets'].join('.'))[0].widget['tasks-widget']; - this.tabToolbarActionsConfig.set(this.homeTabId, homeToolbarConfig); this.createToolbar(this.toolbarContainer.nativeElement, this.homeTabId); this._register(this.themeService.onDidColorThemeChange((event: IColorTheme) => { @@ -179,58 +172,52 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig })); } - private getExtensionContributedHomeToolbarContent(content: ITaskbarContent[]): void { - let primary: IAction[] = []; - let secondary: IAction[] = []; - const menu = this.menuService.createMenu(MenuId.DashboardToolbar, this.contextKeyService); - let groups = menu.getActions({ arg: null, shouldForwardArgs: true }); - fillInActions(groups, { primary, secondary }, false, (group: string) => group === undefined || group === ''); + private getContributedTasks(tabId: string): ITaskbarContent[] { + const tasks: ITaskbarContent[] = []; + // for now we only allow contributing to the home tab toolbar. + if (tabId === this.homeTabId) { + let primary: IAction[] = []; + let secondary: IAction[] = []; + const menu = this.menuService.createMenu(MenuId.DashboardToolbar, this.contextKeyService); + let groups = menu.getActions({ arg: null, shouldForwardArgs: true }); + fillInActions(groups, { primary, secondary }, false, (group: string) => group === undefined || group === ''); - primary.forEach(a => { - if (a instanceof MenuItemAction) { - // Need to ensure that we don't add the same action multiple times - let foundIndex = firstIndex(content, act => act.action && act.action.id === a.id); - if (foundIndex < 0) { - content.push({ action: a }); + primary.forEach(a => { + if (a instanceof MenuItemAction) { + // Need to ensure that we don't add the same action multiple times + let foundIndex = firstIndex(tasks, act => act.action && act.action.id === a.id); + if (foundIndex < 0) { + tasks.push({ action: a }); + } } + }); + + if (primary.length > 0) { + let separator: HTMLElement = Taskbar.createTaskbarSeparator(); + tasks.push({ element: separator }); } - }); - - if (primary.length > 0) { - let separator: HTMLElement = Taskbar.createTaskbarSeparator(); - content.push({ element: separator }); } + return tasks; } - private hasExtensionContributedToolbarContent(): boolean { - let primary: IAction[] = []; - let secondary: IAction[] = []; - const menu = this.menuService.createMenu(MenuId.DashboardToolbar, this.contextKeyService); - let groups = menu.getActions({ arg: null, shouldForwardArgs: true }); - fillInActions(groups, { primary, secondary }, false, (group: string) => group === undefined || group === ''); - return primary.length > 0 || secondary.length > 0; - } - - private createToolbar(parentElement: HTMLElement, tabName: string): void { + private createToolbar(parentElement: HTMLElement, tabId: string): void { // clear out toolbar DOM.clearNode(parentElement); this.toolbar = this._register(new Taskbar(parentElement, { actionViewItemProvider: action => this.createActionItemProvider(action as Action) })); - let content = []; - content = this.getToolbarContent(this.tabToolbarActionsConfig.get(tabName)); - - if (tabName === this.homeTabId) { + content = this.getToolbarContent(tabId); + if (tabId === this.homeTabId) { const configureDashboardCommand = MenuRegistry.getCommand('configureDashboard'); const configureDashboardAction = new ToolbarAction(configureDashboardCommand.id, configureDashboardCommand.title.toString(), TaskRegistry.getOrCreateTaskIconClassName(configureDashboardCommand), this.runAction, this, this.logService); content.push({ action: configureDashboardAction }); } - this.toolbar.setContent(content); } - private getToolbarContent(toolbarTasks: WidgetConfig): ITaskbarContent[] { + private getToolbarContent(tabId: string): ITaskbarContent[] { + const toolbarTasks = this.tabToolbarActionsConfig.get(tabId); let tasks = TaskRegistry.getTasks(); - let content; + let content = []; if (types.isArray(toolbarTasks) && toolbarTasks.length > 0) { tasks = toolbarTasks.map(i => { if (types.isString(i)) { @@ -250,9 +237,12 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig } // get extension actions contributed to the page's toolbar - this.getExtensionContributedHomeToolbarContent(content); + const contributedTasks = this.getContributedTasks(tabId); + content.push(...contributedTasks); - const refreshAction = new RefreshWidgetAction(this.refresh, this); + const refreshAction = new RefreshWidgetAction(() => { + this.refresh(); + }, this); content.push({ action: refreshAction }); return content; } @@ -456,12 +446,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig configs = cb.apply(this, [configs]); }); - // remove tasks widget because the tasks will be shown in the toolbar - const index = configs.findIndex(c => c.widget['tasks-widget']); - if (index !== -1) { - this.tabToolbarActionsConfig.set(value.id, configs[index].widget['tasks-widget']); - configs.splice(index, 1); - } + this.processTasksWidgets(configs, value.id); if (key === WIDGETS_CONTAINER) { return { id: value.id, title: value.title, container: { 'widgets-container': configs }, alwaysShow: value.alwaysShow, iconClass: value.iconClass }; @@ -473,6 +458,28 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig return { id: value.id, title: value.title, container: containerResult.container, alwaysShow: value.alwaysShow, iconClass: value.iconClass }; } + /** + * Process the tasks widgets, tasks widgets has been deprecated and the tasks are now in toolbar. + * @param widgets widgets + * @param tabId tab id + */ + private processTasksWidgets(widgets: WidgetConfig[], tabId: string): void { + let index; + const allTasks = []; + // do this in a while loop since there might be multiple tasks widgets in a tab + do { + index = widgets.findIndex(c => c.widget['tasks-widget']); + if (index !== -1) { + const tasks = widgets[index].widget['tasks-widget']; + if (Array.isArray(tasks)) { + allTasks.push(...tasks); + } + widgets.splice(index, 1); + } + } while (index !== -1); + this.tabToolbarActionsConfig.set(tabId, allTasks); + } + protected getContentType(tab: TabConfig): string { return tab.container ? Object.keys(tab.container)[0] : ''; } @@ -525,8 +532,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig public handleTabChange(tab: TabComponent): void { this._tabName.set(tab.identifier); const tabContent = this.tabContents.get(tab.identifier); - if (tab.identifier === this.homeTabId || tabContent === WIDGETS_CONTAINER || tabContent === GRID_CONTAINER || tabContent === NAV_SECTION - || this.hasExtensionContributedToolbarContent()) { + if (tab.identifier === this.homeTabId || tabContent === WIDGETS_CONTAINER || tabContent === GRID_CONTAINER || tabContent === NAV_SECTION) { this.showToolbar = true; this.createToolbar(this.toolbarContainer.nativeElement, tab.identifier); } else { // hide toolbar @@ -534,9 +540,6 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig } this._cd.detectChanges(); - const localtab = this._tabs.find(i => i.id === tab.identifier); - this._editEnabled.fire(localtab.editable); - this._cd.detectChanges(); } public handleTabClose(tab: TabComponent): void { diff --git a/src/sql/workbench/contrib/dashboard/browser/core/dashboardWidget.ts b/src/sql/workbench/contrib/dashboard/browser/core/dashboardWidget.ts index 0e3c9b7766..f2ec77ab70 100644 --- a/src/sql/workbench/contrib/dashboard/browser/core/dashboardWidget.ts +++ b/src/sql/workbench/contrib/dashboard/browser/core/dashboardWidget.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { InjectionToken, OnDestroy } from '@angular/core'; +import { InjectionToken, OnDestroy, ChangeDetectorRef } from '@angular/core'; import { NgGridItemConfig } from 'angular2-grid'; import { Action } from 'vs/base/common/actions'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -63,6 +63,14 @@ export interface TabSettingConfig { export abstract class DashboardWidget extends Disposable implements OnDestroy { protected _config: WidgetConfig; + protected _loading: boolean; + protected _inited: boolean = false; + protected _loadingMessage: string; + protected _loadingCompletedMessage: string; + + constructor(protected _changeRef: ChangeDetectorRef) { + super(); + } get actions(): Array { return []; @@ -71,4 +79,11 @@ export abstract class DashboardWidget extends Disposable implements OnDestroy { ngOnDestroy() { this.dispose(); } + + protected setLoadingStatus(loading: boolean): void { + this._loading = loading; + if (this._inited) { + this._changeRef.detectChanges(); + } + } } diff --git a/src/sql/workbench/contrib/dashboard/browser/dashboard.module.ts b/src/sql/workbench/contrib/dashboard/browser/dashboard.module.ts index 0686f623d5..bc70d305f4 100644 --- a/src/sql/workbench/contrib/dashboard/browser/dashboard.module.ts +++ b/src/sql/workbench/contrib/dashboard/browser/dashboard.module.ts @@ -82,7 +82,6 @@ const pageComponents = [ServerDashboardPage, DatabaseDashboardPage]; /* Widget Components */ import { PropertiesWidgetComponent } from 'sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component'; import { ExplorerWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component'; -import { TasksWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component'; import { InsightsWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component'; import { WebviewWidget } from 'sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component'; import { JobStepsViewComponent } from 'sql/workbench/contrib/jobManagement/browser/jobStepsView.component'; @@ -93,7 +92,6 @@ import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; const widgetComponents = [ PropertiesWidgetComponent, ExplorerWidget, - TasksWidget, InsightsWidget, WebviewWidget ]; diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.html b/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.html index 9809cd426e..505909e405 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.html +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.html @@ -4,11 +4,12 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ --> -
+
- +
diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.ts index 469c0d9b4c..470187e678 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.component.ts @@ -47,11 +47,6 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget, private _treeDataSource = new ExplorerDataSource(); private _treeFilter = new ExplorerFilter(); - private _inited = false; - public loading: boolean = false; - public loadingMessage: string; - public loadingCompletedMessage: string; - @ViewChild('input') private _inputContainer: ElementRef; @ViewChild('table') private _tableContainer: ElementRef; @@ -64,11 +59,11 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget, @Inject(IContextViewService) private readonly contextViewService: IContextViewService, @Inject(IInstantiationService) private readonly instantiationService: IInstantiationService, @Inject(ICapabilitiesService) private readonly capabilitiesService: ICapabilitiesService, - @Inject(forwardRef(() => ChangeDetectorRef)) private readonly _cd: ChangeDetectorRef + @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef ) { - super(); - this.loadingMessage = this._config.context === 'database' ? nls.localize('loadingObjects', "loading objects") : nls.localize('loadingDatabases', "loading databases"); - this.loadingCompletedMessage = this._config.context === 'database' ? nls.localize('loadingObjectsCompleted', "loading objects completed.") : nls.localize('loadingDatabasesCompleted', "loading databases completed."); + super(changeRef); + this._loadingMessage = this._config.context === 'database' ? nls.localize('loadingObjects', "loading objects") : nls.localize('loadingDatabases', "loading databases"); + this._loadingCompletedMessage = this._config.context === 'database' ? nls.localize('loadingObjectsCompleted', "loading objects completed.") : nls.localize('loadingDatabasesCompleted', "loading databases completed."); this.init(); } @@ -167,14 +162,6 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget, } } - private setLoadingStatus(loading: boolean): void { - this.loading = loading; - - if (this._inited) { - this._cd.detectChanges(); - } - } - private showErrorMessage(message: string): void { (this._el.nativeElement).innerText = message; alert(message); diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component.ts index d6055655b7..3c19445d4b 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.component.ts @@ -49,8 +49,8 @@ interface IStorageResult {
{{lastUpdated}}
{{autoRefreshStatus}}
- - + +
`, styles: [':host { width: 100%; height: 100% }'] }) @@ -60,8 +60,6 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, @ViewChild(ComponentHostDirective) private componentHost: ComponentHostDirective; private _typeKey: string; - private _init: boolean = false; - public _loading: boolean = true; private _intervalTimer: IntervalTimer; public error: string; @@ -72,16 +70,17 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, @Inject(forwardRef(() => ComponentFactoryResolver)) private _componentFactoryResolver: ComponentFactoryResolver, @Inject(forwardRef(() => CommonServiceInterface)) private dashboardService: CommonServiceInterface, @Inject(WIDGET_CONFIG) protected _config: WidgetConfig, - @Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef, + @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef, @Inject(forwardRef(() => Injector)) private _injector: Injector, @Inject(IInstantiationService) private instantiationService: IInstantiationService, @Inject(IStorageService) private storageService: IStorageService, @Inject(IConfigurationService) private readonly _configurationService: IConfigurationService, @Inject(IFileService) private readonly fileService: IFileService ) { - super(); + super(changeRef); this.insightConfig = this._config.widget['insights-widget']; - + this._loadingMessage = nls.localize('insightsWidgetLoadingMessage', "Loading {0}", this._config.name); + this._loadingCompletedMessage = nls.localize('insightsWidgetLoadingCompletedMessage', "Loading {0} completed", this._config.name); this._verifyConfig(); this._parseConfig().then(() => { @@ -91,8 +90,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, const cancelablePromise = createCancelablePromise(() => { return promise.then( result => { - this._loading = false; - if (this._init) { + if (this._inited) { this._updateChild(result); this.setupInterval(); } else { @@ -100,37 +98,36 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, } }, error => { - this._loading = false; if (isPromiseCanceledError(error)) { return; } - if (this._init) { + if (this._inited) { this.showError(error); } else { this.queryObv = Observable.fromPromise(Promise.resolve(error)); } } - ).then(() => this._cd.detectChanges()); + ).then(() => this._changeRef.detectChanges()); }); this._register(toDisposable(() => cancelablePromise.cancel())); } }, error => { - this._loading = false; + this.setLoadingStatus(false); this.showError(error); }); } ngAfterContentInit() { - this._init = true; + this._inited = true; if (this.queryObv) { this._register(subscriptionToDisposable(this.queryObv.subscribe( result => { - this._loading = false; + this.setLoadingStatus(false); this._updateChild(result); this.setupInterval(); }, error => { - this._loading = false; + this.setLoadingStatus(false); this.showError(error); } ))); @@ -156,13 +153,13 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, let newState = autoRefreshOn ? '' : nls.localize('insights.autoRefreshOffState', "Auto Refresh: OFF"); if (this.autoRefreshStatus !== newState) { this.autoRefreshStatus = newState; - this._cd.detectChanges(); + this._changeRef.detectChanges(); } } private showError(error: string): void { this.error = error; - this._cd.detectChanges(); + this._changeRef.detectChanges(); } get actions(): Array { @@ -189,7 +186,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, results: result }; this.lastUpdated = nls.localize('insights.lastUpdated', "Last Updated: {0} {1}", currentTime.toLocaleTimeString(), currentTime.toLocaleDateString()); - this._cd.detectChanges(); + this._changeRef.detectChanges(); this.storageService.store(this._getStorageKey(), JSON.stringify(store), StorageScope.GLOBAL); } return result; @@ -202,11 +199,10 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, const storedResult: IStorageResult = JSON.parse(storage); const date = new Date(storedResult.date); this.lastUpdated = nls.localize('insights.lastUpdated', "Last Updated: {0} {1}", date.toLocaleTimeString(), date.toLocaleDateString()); - this._loading = false; - if (this._init) { + if (this._inited) { this._updateChild(storedResult.results); this.setupInterval(); - this._cd.detectChanges(); + this._changeRef.detectChanges(); } else { this.queryObv = Observable.fromPromise(Promise.resolve(JSON.parse(storage))); } @@ -231,11 +227,14 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, } private _runQuery(): Promise { + this.setLoadingStatus(true); return Promise.resolve(this.dashboardService.queryManagementService.runQueryAndReturn(this.insightConfig.query as string).then( result => { + this.setLoadingStatus(false); return this._storeResult(result); }, error => { + this.setLoadingStatus(false); throw error; } )); @@ -244,7 +243,7 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget, private _updateChild(result: SimpleExecuteResult): void { this.componentHost.viewContainerRef.clear(); this.error = undefined; - this._cd.detectChanges(); + this._changeRef.detectChanges(); if (result.rowCount === 0) { this.showError(nls.localize('noResults', "No results to show")); diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.html b/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.html index ea0b43bc0b..803376e0ae 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.html +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.html @@ -4,7 +4,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ --> -
+ +
diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.ts index 2e474bea23..5b6766ffde 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/properties/propertiesWidget.component.ts @@ -68,7 +68,6 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb private _databaseInfo: DatabaseInfo; public _clipped: boolean; private properties: Array; - private _hasInit = false; @ViewChild('child', { read: ElementRef }) private _child: ElementRef; @ViewChild('parent', { read: ElementRef }) private _parent: ElementRef; @@ -76,18 +75,20 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb constructor( @Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface, - @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, + @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef, @Inject(forwardRef(() => ElementRef)) private _el: ElementRef, @Inject(WIDGET_CONFIG) protected _config: WidgetConfig, @Inject(ILogService) private logService: ILogService, @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService ) { - super(); + super(changeRef); + this._loadingMessage = nls.localize('loadingProperties', "Loading properties"); + this._loadingCompletedMessage = nls.localize('loadingPropertiesCompleted', "Loading properties completed"); this.init(); } ngOnInit() { - this._hasInit = true; + this._inited = true; this._register(addDisposableListener(window, EventType.RESIZE, () => this.handleClipping())); this._changeRef.detectChanges(); @@ -106,14 +107,17 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb private init(): void { this._connection = this._bootstrap.connectionManagementService.connectionInfo; + this.setLoadingStatus(true); this._register(subscriptionToDisposable(this._bootstrap.adminService.databaseInfo.subscribe(data => { this._databaseInfo = data; this._changeRef.detectChanges(); this.parseProperties(); - if (this._hasInit) { + if (this._inited) { this.handleClipping(); } + this.setLoadingStatus(false); }, error => { + this.setLoadingStatus(false); (this._el.nativeElement).innerText = nls.localize('dashboard.properties.error', "Unable to load dashboard properties"); }))); } @@ -238,7 +242,7 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb this.properties.push(assignProperty); } - if (this._hasInit) { + if (this._inited) { this._changeRef.detectChanges(); } } diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/media/taskWidget.css b/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/media/taskWidget.css deleted file mode 100644 index a0e762fda8..0000000000 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/media/taskWidget.css +++ /dev/null @@ -1,32 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -tasks-widget .tile-container { - position: relative; - display: flex; - flex-flow: row wrap; - align-content: flex-start; -} - -tasks-widget .task-tile { - cursor: pointer; - display: flex; - flex-flow: row; - align-items: center; - text-align: center; - margin-top: 10px; - margin-left: 18px; -} - -tasks-widget .task-tile > div { - flex: 1 1 auto; - display: flex; - flex-flow: column; - align-items: center; -} - -tasks-widget .task-tile .codicon { - padding: 15px; -} diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.html b/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.html deleted file mode 100644 index e708a6d6a4..0000000000 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.html +++ /dev/null @@ -1,8 +0,0 @@ - -
-
diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.ts deleted file mode 100644 index 27c546dd19..0000000000 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.component.ts +++ /dev/null @@ -1,178 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!sql/media/icons/common-icons'; -import 'vs/css!./media/taskWidget'; - -/* Node Modules */ -import { Component, Inject, forwardRef, ViewChild, OnInit, ElementRef } from '@angular/core'; - -/* SQL imports */ -import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget'; -import { CommonServiceInterface } from 'sql/workbench/services/bootstrap/browser/commonServiceInterface.service'; -import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; - -/* VS imports */ -import * as themeColors from 'vs/workbench/common/theme'; -import * as colors from 'vs/platform/theme/common/colorRegistry'; -import { registerThemingParticipant, ICssStyleCollector, IColorTheme } from 'vs/platform/theme/common/themeService'; -import * as types from 'vs/base/common/types'; -import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; -import { ScrollbarVisibility } from 'vs/base/common/scrollable'; -import * as DOM from 'vs/base/browser/dom'; -import { ICommandService } from 'vs/platform/commands/common/commands'; -import { MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { KeyCode } from 'vs/base/common/keyCodes'; -import { TaskRegistry } from 'sql/workbench/services/tasks/browser/tasksRegistry'; - -interface ITask { - name: string; - when: string; -} - -const selector = 'tasks-widget'; - -@Component({ - selector, - templateUrl: decodeURI(require.toUrl('./tasksWidget.component.html')) -}) -export class TasksWidget extends DashboardWidget implements IDashboardWidget, OnInit { - private _size: number = 98; - private _tasks: Array = []; - private _profile: IConnectionProfile; - private _scrollableElement: ScrollableElement; - private _tileContainer: HTMLElement; - static readonly ICON_PATH_TO_CSS_RULES: Map = new Map(); - - private _inited = false; - - @ViewChild('container', { read: ElementRef }) private _container: ElementRef; - - constructor( - @Inject(WIDGET_CONFIG) protected _config: WidgetConfig, - @Inject(forwardRef(() => CommonServiceInterface)) private readonly _bootstrap: CommonServiceInterface, - @Inject(ICommandService) private readonly commandService: ICommandService, - @Inject(IContextKeyService) readonly contextKeyService: IContextKeyService - ) { - super(); - this._profile = this._bootstrap.connectionManagementService.connectionInfo.connectionProfile; - const tasksConfig = this._config.widget[selector] as Array; - let tasks = TaskRegistry.getTasks(); - - if (types.isArray(tasksConfig) && tasksConfig.length > 0) { - tasks = tasksConfig.map(i => { - if (types.isString(i)) { - if (tasks.some(x => x === i)) { - return i; - } - } else { - if (tasks.some(x => x === i.name) && contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(i.when))) { - return i.name; - } - } - return undefined; - }).filter(i => !!i); - } - - this._tasks = tasks.map(i => MenuRegistry.getCommand(i)).filter(v => !!v); - } - - ngOnInit() { - this._inited = true; - this._register(registerThemingParticipant(this.registerThemeing)); - this._computeContainer(); - - this._tasks.map(a => { - this._tileContainer.append(this._createTile(a)); - }); - - this._scrollableElement = this._register(new ScrollableElement(this._tileContainer, { - horizontal: ScrollbarVisibility.Auto, - vertical: ScrollbarVisibility.Hidden, - scrollYToX: true, - useShadows: false - })); - - this._scrollableElement.onScroll(e => { - this._tileContainer.style.right = e.scrollLeft + 'px'; - }); - - (this._container.nativeElement as HTMLElement).appendChild(this._scrollableElement.getDomNode()); - - // Update scrollbar - this._scrollableElement.setScrollDimensions({ - width: DOM.getContentWidth(this._container.nativeElement), - scrollWidth: DOM.getContentWidth(this._tileContainer) + 18 // right padding - }); - } - - private _computeContainer(): void { - const height = DOM.getContentHeight(this._container.nativeElement); - const tilesHeight = Math.floor(height / (this._size + 10)); - const width = (this._size + 18) * Math.ceil(this._tasks.length / tilesHeight); - if (!this._tileContainer) { - this._tileContainer = DOM.$('.tile-container'); - } - this._tileContainer.style.height = height + 'px'; - this._tileContainer.style.width = width + 'px'; - } - - private _createTile(action: ICommandAction): HTMLElement { - const label = DOM.$('div'); - label.innerText = types.isString(action.title) ? action.title : action.title.value; - const tile = DOM.$('.task-tile'); - tile.style.height = this._size + 'px'; - tile.style.width = this._size + 'px'; - const innerTile = DOM.$('div'); - - const iconClassName = TaskRegistry.getOrCreateTaskIconClassName(action); - if (iconClassName) { - const icon = DOM.$('span.codicon'); - DOM.addClass(icon, iconClassName); - innerTile.append(icon); - } - innerTile.append(label); - tile.append(innerTile); - tile.setAttribute('tabindex', '0'); - this._register(DOM.addDisposableListener(tile, DOM.EventType.CLICK, () => this.runTask(action))); - this._register(DOM.addDisposableListener(tile, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { - const event = new StandardKeyboardEvent(e); - if (event.equals(KeyCode.Enter)) { - this.runTask(action); - e.stopImmediatePropagation(); - } - })); - return tile; - } - - private registerThemeing(theme: IColorTheme, collector: ICssStyleCollector) { - const contrastBorder = theme.getColor(colors.contrastBorder); - const sideBarColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND); - if (contrastBorder) { - const contrastBorderString = contrastBorder.toString(); - collector.addRule(`tasks-widget .task-tile { border: 1px solid ${contrastBorderString} }`); - } else { - const sideBarColorString = sideBarColor.toString(); - collector.addRule(`tasks-widget .task-tile { background-color: ${sideBarColorString} }`); - } - } - - public runTask(task: ICommandAction) { - this.commandService.executeCommand(task.id, this._profile); - } - - public layout(): void { - if (this._inited) { - this._computeContainer(); - // Update scrollbar - this._scrollableElement.setScrollDimensions({ - width: DOM.getContentWidth(this._container.nativeElement), - scrollWidth: DOM.getContentWidth(this._tileContainer) + 18 // right padding - }); - } - } -} diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.contribution.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.contribution.ts deleted file mode 100644 index cc18042af6..0000000000 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.contribution.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { registerDashboardWidget } from 'sql/platform/dashboard/browser/widgetRegistry'; - -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { TaskRegistry } from 'sql/workbench/services/tasks/browser/tasksRegistry'; - -const singleTaskSchema: IJSONSchema = { - type: 'string', - enum: TaskRegistry.getTasks() -}; - -const tasksSchema: IJSONSchema = { - type: 'array', - items: { - anyOf: [ - singleTaskSchema, - { - type: 'object', - properties: { - name: singleTaskSchema, - when: { - type: 'string' - } - } - } - ] - } -}; - -TaskRegistry.onTaskRegistered(e => { - singleTaskSchema.enum.push(e); -}); - -registerDashboardWidget('tasks-widget', '', tasksSchema); diff --git a/src/sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component.ts b/src/sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component.ts index 013eb9b324..6c49f762ff 100644 --- a/src/sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component.ts +++ b/src/sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.component.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Component, Inject, forwardRef, OnInit, ElementRef } from '@angular/core'; +import { Component, Inject, forwardRef, OnInit, ElementRef, ChangeDetectorRef } from '@angular/core'; import { Event, Emitter } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; @@ -41,9 +41,10 @@ export class WebviewWidget extends DashboardWidget implements IDashboardWidget, @Inject(WIDGET_CONFIG) protected readonly _config: WidgetConfig, @Inject(forwardRef(() => ElementRef)) private readonly _el: ElementRef, @Inject(IDashboardViewService) private readonly dashboardViewService: IDashboardViewService, - @Inject(IWebviewService) private readonly webviewService: IWebviewService + @Inject(IWebviewService) private readonly webviewService: IWebviewService, + @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef ) { - super(); + super(changeRef); this._id = (_config.widget[selector] as IWebviewWidgetConfig).id; } diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 24bb3f9e1a..0155d3e111 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -435,7 +435,6 @@ import 'sql/workbench/contrib/dashboard/browser/widgets/insights/views/tableInsi import 'sql/workbench/contrib/dashboard/browser/dashboard.contribution'; import 'sql/workbench/contrib/dashboard/browser/widgets/insights/insightsWidget.contribution'; import 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerWidget.contribution'; -import 'sql/workbench/contrib/dashboard/browser/widgets/tasks/tasksWidget.contribution'; import 'sql/workbench/contrib/dashboard/browser/widgets/webview/webviewWidget.contribution'; import 'sql/workbench/contrib/dashboard/browser/containers/dashboardWebviewContainer.contribution'; import 'sql/workbench/contrib/dashboard/browser/containers/dashboardControlHostContainer.contribution';