fix properties widget (#9693)

* fix properties widget

* handle error scenario
This commit is contained in:
Alan Ren
2020-03-23 12:10:24 -07:00
committed by GitHub
parent 5a0dd18cba
commit c35221c076
3 changed files with 78 additions and 12 deletions

View File

@@ -4,20 +4,44 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/loadingComponent'; import 'vs/css!./media/loadingComponent';
import { Component, Input } from '@angular/core'; import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import * as nls from 'vs/nls'; import * as nls from 'vs/nls';
import { status } from 'vs/base/browser/ui/aria/aria';
const DefaultLoadingMessage = nls.localize('loadingMessage', "Loading");
const DefaultLoadingCompletedMessage = nls.localize('loadingCompletedMessage', "Loading completed");
@Component({ @Component({
selector: 'loading-spinner', selector: 'loading-spinner',
template: ` template: `
<div class="modelview-loadingComponent-container" *ngIf="loading"> <div class="modelview-loadingComponent-container" *ngIf="loading">
<div class="modelview-loadingComponent-spinner" *ngIf="loading" [title]=_loadingTitle #spinnerElement></div> <div class="modelview-loadingComponent-spinner" *ngIf="loading" [title]="_loadingMessage" #spinnerElement></div>
</div> </div>
` `
}) })
export default class LoadingSpinner { export default class LoadingSpinner implements OnChanges {
public readonly _loadingTitle = nls.localize('loadingMessage', "Loading");
@Input() loading: boolean; ngOnChanges(changes: SimpleChanges): void {
if (changes.loading !== undefined) {
const message = this.loading ? this._loadingMessage : this._loadingCompletedMessage;
status(message);
}
}
get _loadingMessage(): string {
return this.loadingMessage ? this.loadingMessage : DefaultLoadingMessage;
}
get _loadingCompletedMessage(): string {
return this.loadingCompletedMessage ? this.loadingCompletedMessage : DefaultLoadingCompletedMessage;
}
@Input()
loading: boolean;
@Input()
loadingMessage: string;
@Input()
loadingCompletedMessage: string;
} }

View File

@@ -7,6 +7,8 @@
<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 #input style="width: 100%"></div>
<div style="flex: 1 1 auto; position: relative"> <div style="flex: 1 1 auto; position: relative">
<loading-spinner [loading]="loading" [loadingMessage]="loadingMessage"
[loadingCompletedMessage]="loadingCompletedMessage"></loading-spinner>
<div #table style="position: absolute; height: 100%; width: 100%"></div> <div #table style="position: absolute; height: 100%; width: 100%"></div>
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@
import 'vs/css!sql/media/icons/common-icons'; import 'vs/css!sql/media/icons/common-icons';
import 'vs/css!./media/explorerWidget'; import 'vs/css!./media/explorerWidget';
import { Component, Inject, forwardRef, OnInit, ViewChild, ElementRef } from '@angular/core'; import { Component, Inject, forwardRef, OnInit, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget'; import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/contrib/dashboard/browser/core/dashboardWidget';
@@ -27,6 +27,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { subscriptionToDisposable } from 'sql/base/browser/lifecycle'; import { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
import { ObjectMetadataWrapper } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/objectMetadataWrapper'; import { ObjectMetadataWrapper } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/objectMetadataWrapper';
import { status, alert } from 'vs/base/browser/ui/aria/aria';
@Component({ @Component({
selector: 'explorer-widget', selector: 'explorer-widget',
@@ -47,6 +48,9 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
private _treeFilter = new ExplorerFilter(); private _treeFilter = new ExplorerFilter();
private _inited = false; private _inited = false;
public loading: boolean = false;
public loadingMessage: string;
public loadingCompletedMessage: string;
@ViewChild('input') private _inputContainer: ElementRef; @ViewChild('input') private _inputContainer: ElementRef;
@ViewChild('table') private _tableContainer: ElementRef; @ViewChild('table') private _tableContainer: ElementRef;
@@ -59,9 +63,12 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
@Inject(IWorkbenchThemeService) private readonly themeService: IWorkbenchThemeService, @Inject(IWorkbenchThemeService) private readonly themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private readonly contextViewService: IContextViewService, @Inject(IContextViewService) private readonly contextViewService: IContextViewService,
@Inject(IInstantiationService) private readonly instantiationService: IInstantiationService, @Inject(IInstantiationService) private readonly instantiationService: IInstantiationService,
@Inject(ICapabilitiesService) private readonly capabilitiesService: ICapabilitiesService @Inject(ICapabilitiesService) private readonly capabilitiesService: ICapabilitiesService,
@Inject(forwardRef(() => ChangeDetectorRef)) private readonly _cd: ChangeDetectorRef
) { ) {
super(); 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.");
this.init(); this.init();
} }
@@ -76,9 +83,25 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
}; };
this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions); this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions);
this._register(this._input.onDidChange(e => { this._register(this._input.onDidChange(e => {
this._filterDelayer.trigger(() => { this._filterDelayer.trigger(async () => {
this._treeFilter.filterString = e; this._treeFilter.filterString = e;
this._tree.refresh(); await this._tree.refresh();
const navigator = this._tree.getNavigator();
let item = navigator.next();
let count = 0;
while (item) {
count++;
item = navigator.next();
}
let message: string;
if (count === 0) {
message = nls.localize('explorerSearchNoMatchResultMessage', "No matching item found");
} else if (count === 1) {
message = nls.localize('explorerSearchSingleMatchResultMessage', "Filtered search list to 1 item");
} else {
message = nls.localize('explorerSearchMatchResultMessage', "Filtered search list to {0} items", count);
}
status(message);
}); });
})); }));
this._tree = new Tree(this._tableContainer.nativeElement, { this._tree = new Tree(this._tableContainer.nativeElement, {
@@ -95,6 +118,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
} }
private init(): void { private init(): void {
this.setLoadingStatus(true);
if (this._config.context === 'database') { if (this._config.context === 'database') {
this._register(subscriptionToDisposable(this._bootstrap.metadataService.metadata.subscribe( this._register(subscriptionToDisposable(this._bootstrap.metadataService.metadata.subscribe(
data => { data => {
@@ -103,10 +128,11 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
objectData.sort(ObjectMetadataWrapper.sort); objectData.sort(ObjectMetadataWrapper.sort);
this._treeDataSource.data = objectData; this._treeDataSource.data = objectData;
this._tree.setInput(new ExplorerModel()); this._tree.setInput(new ExplorerModel());
this.setLoadingStatus(false);
} }
}, },
error => { error => {
(<HTMLElement>this._el.nativeElement).innerText = nls.localize('dashboard.explorer.objectError', "Unable to load objects"); this.showErrorMessage(nls.localize('dashboard.explorer.objectError', "Unable to load objects"));
} }
))); )));
} else { } else {
@@ -122,9 +148,10 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
}); });
this._treeDataSource.data = profileData; this._treeDataSource.data = profileData;
this._tree.setInput(new ExplorerModel()); this._tree.setInput(new ExplorerModel());
this.setLoadingStatus(false);
}, },
error => { error => {
(<HTMLElement>this._el.nativeElement).innerText = nls.localize('dashboard.explorer.databaseError', "Unable to load databases"); this.showErrorMessage(nls.localize('dashboard.explorer.databaseError', "Unable to load databases"));
} }
))); )));
} }
@@ -139,4 +166,17 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
this._tree.layout(getContentHeight(this._tableContainer.nativeElement)); this._tree.layout(getContentHeight(this._tableContainer.nativeElement));
} }
} }
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);
}
} }