diff --git a/src/sql/workbench/browser/modelComponents/loadingSpinner.component.ts b/src/sql/workbench/browser/modelComponents/loadingSpinner.component.ts
index 172438d5e3..2c09893a10 100644
--- a/src/sql/workbench/browser/modelComponents/loadingSpinner.component.ts
+++ b/src/sql/workbench/browser/modelComponents/loadingSpinner.component.ts
@@ -4,20 +4,44 @@
*--------------------------------------------------------------------------------------------*/
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 { status } from 'vs/base/browser/ui/aria/aria';
+
+const DefaultLoadingMessage = nls.localize('loadingMessage', "Loading");
+const DefaultLoadingCompletedMessage = nls.localize('loadingCompletedMessage', "Loading completed");
@Component({
selector: 'loading-spinner',
template: `
`
})
-export default class LoadingSpinner {
- public readonly _loadingTitle = nls.localize('loadingMessage', "Loading");
+export default class LoadingSpinner implements OnChanges {
- @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;
}
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 3d688ee76a..9809cd426e 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
@@ -7,6 +7,8 @@
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 7750e4cb11..469c0d9b4c 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
@@ -6,7 +6,7 @@
import 'vs/css!sql/media/icons/common-icons';
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 { 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 { subscriptionToDisposable } from 'sql/base/browser/lifecycle';
import { ObjectMetadataWrapper } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/objectMetadataWrapper';
+import { status, alert } from 'vs/base/browser/ui/aria/aria';
@Component({
selector: 'explorer-widget',
@@ -47,6 +48,9 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
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;
@@ -59,9 +63,12 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
@Inject(IWorkbenchThemeService) private readonly themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private readonly contextViewService: IContextViewService,
@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();
+ 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();
}
@@ -76,9 +83,25 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
};
this._input = new InputBox(this._inputContainer.nativeElement, this.contextViewService, inputOptions);
this._register(this._input.onDidChange(e => {
- this._filterDelayer.trigger(() => {
+ this._filterDelayer.trigger(async () => {
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, {
@@ -95,6 +118,8 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
}
private init(): void {
+ this.setLoadingStatus(true);
+
if (this._config.context === 'database') {
this._register(subscriptionToDisposable(this._bootstrap.metadataService.metadata.subscribe(
data => {
@@ -103,10 +128,11 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
objectData.sort(ObjectMetadataWrapper.sort);
this._treeDataSource.data = objectData;
this._tree.setInput(new ExplorerModel());
+ this.setLoadingStatus(false);
}
},
error => {
- (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 {
@@ -122,9 +148,10 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget,
});
this._treeDataSource.data = profileData;
this._tree.setInput(new ExplorerModel());
+ this.setLoadingStatus(false);
},
error => {
- (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));
}
}
+
+ 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);
+ }
}