mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
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
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,4 +69,9 @@ export class DashboardHomeContainer extends DashboardWidgetContainer {
|
||||
this._scrollable.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
super.refresh();
|
||||
this._propertiesClass.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IDashboardWidget> } = {
|
||||
'properties-widget': PropertiesWidgetComponent,
|
||||
'explorer-widget': ExplorerWidget,
|
||||
'tasks-widget': TasksWidget,
|
||||
'insights-widget': InsightsWidget,
|
||||
'webview-widget': WebviewWidget
|
||||
};
|
||||
|
||||
@@ -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<string, WidgetConfig>();
|
||||
private tabToolbarActionsConfig = new Map<string, any[]>();
|
||||
private tabContents = new Map<string, string>();
|
||||
|
||||
static tabName = new RawContextKey<string>('tabName', undefined);
|
||||
@@ -145,12 +145,7 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
|
||||
});
|
||||
} else {
|
||||
let tempWidgets = this.dashboardService.getSettings<Array<WidgetConfig>>([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<Array<WidgetConfig>>([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 {
|
||||
|
||||
@@ -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<Action> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
];
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div class="explorer-widget" style="display: flex; flex-flow: column; position: absolute; height:100%; width:100%; padding: 10px; box-sizing: border-box">
|
||||
<div class="explorer-widget"
|
||||
style="display: flex; flex-flow: column; position: absolute; height:100%; width:100%; padding: 10px; box-sizing: border-box">
|
||||
<div #input style="width: 100%"></div>
|
||||
<div style="flex: 1 1 auto; position: relative">
|
||||
<loading-spinner [loading]="loading" [loadingMessage]="loadingMessage"
|
||||
[loadingCompletedMessage]="loadingCompletedMessage"></loading-spinner>
|
||||
<loading-spinner [loading]="_loading" [loadingMessage]="_loadingMessage"
|
||||
[loadingCompletedMessage]="_loadingCompletedMessage"></loading-spinner>
|
||||
<div #table style="position: absolute; height: 100%; width: 100%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 {
|
||||
(<HTMLElement>this._el.nativeElement).innerText = message;
|
||||
alert(message);
|
||||
|
||||
@@ -49,8 +49,8 @@ interface IStorageResult {
|
||||
<div *ngIf="lastUpdated" style="font-style: italic; font-size: 80%; margin-left: 5px">{{lastUpdated}}</div>
|
||||
<div *ngIf="autoRefreshStatus" style="font-style: italic; font-size: 80%; margin-left: 5px">{{autoRefreshStatus}}</div>
|
||||
<div style="margin: 10px; width: calc(100% - 20px); height: calc(100% - 20px)">
|
||||
<ng-template component-host></ng-template>
|
||||
<loading-spinner [loading]="_loading"></loading-spinner>
|
||||
<ng-template *ngIf="!_loading" component-host></ng-template>
|
||||
<loading-spinner [loading]="_loading" [loadingMessage]="_loadingMessage" [loadingCompletedMessage]="_loadingCompletedMessage"></loading-spinner>
|
||||
</div>`,
|
||||
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 = <IInsightsConfig>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<SimpleExecuteResult>(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<Action> {
|
||||
@@ -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<SimpleExecuteResult>(JSON.parse(storage)));
|
||||
}
|
||||
@@ -231,11 +227,14 @@ export class InsightsWidget extends DashboardWidget implements IDashboardWidget,
|
||||
}
|
||||
|
||||
private _runQuery(): Promise<SimpleExecuteResult> {
|
||||
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"));
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div #parent style="position: absolute; height: 100%; width: 100%;">
|
||||
<loading-spinner [loading]="_loading" [loadingMessage]="_loadingMessage"
|
||||
[loadingCompletedMessage]="_loadingCompletedMessage"></loading-spinner>
|
||||
<div #parent style="position: absolute; height: 100%; width: 100%;" [style.display]="_loading ? 'none':'block'">
|
||||
<div #container [style.margin-right.px]="_clipped ? 30 : 0" [style.width]="_clipped ? 94 + '%' : '100%'" style="overflow: hidden; padding-bottom: 10px">
|
||||
<span #child style="white-space : nowrap; width: fit-content">
|
||||
<ng-template ngFor let-item [ngForOf]="properties">
|
||||
|
||||
@@ -68,7 +68,6 @@ export class PropertiesWidgetComponent extends DashboardWidget implements IDashb
|
||||
private _databaseInfo: DatabaseInfo;
|
||||
public _clipped: boolean;
|
||||
private properties: Array<DisplayProperty>;
|
||||
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);
|
||||
(<HTMLElement>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(<DisplayProperty>assignProperty);
|
||||
}
|
||||
|
||||
if (this._hasInit) {
|
||||
if (this._inited) {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div #container style="position: absolute; height: 100%; width: 100%">
|
||||
</div>
|
||||
@@ -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<ICommandAction> = [];
|
||||
private _profile: IConnectionProfile;
|
||||
private _scrollableElement: ScrollableElement;
|
||||
private _tileContainer: HTMLElement;
|
||||
static readonly ICON_PATH_TO_CSS_RULES: Map<string /* path*/, string /* CSS rule */> = new Map<string, string>();
|
||||
|
||||
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<string | ITask>;
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user