diff --git a/src/sql/base/browser/ui/table/plugins/loadingSpinner.plugin.ts b/src/sql/base/browser/ui/table/plugins/loadingSpinner.plugin.ts new file mode 100644 index 0000000000..a157d95ef5 --- /dev/null +++ b/src/sql/base/browser/ui/table/plugins/loadingSpinner.plugin.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * 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!./media/loadingSpinner.plugin'; + +import * as DOM from 'vs/base/browser/dom'; +import { localize } from 'vs/nls'; + +/** + * Plugin that will hide the viewport and display a loading spinner when set to loading + */ + +const loadingText = localize('loadingSpinner.loading', "Loading"); + +export class LoadingSpinnerPlugin implements Slick.Plugin { + + private _container!: HTMLElement; + private _viewport!: HTMLElement; + private _loadingContainer!: HTMLElement; + private _loading = false; + + public init(grid: Slick.Grid): void { + this._loadingContainer = DOM.$('div.loading-spinner-plugin-container'); + this._container = grid.getContainerNode(); + this._viewport = this._container.getElementsByClassName('slick-viewport')[0] as HTMLElement; + this._viewport.parentElement.insertBefore(this._loadingContainer, this._viewport); + } + + public destroy(): void { } + + public set loading(isLoading: boolean) { + if (isLoading) { + if (!this._loading) { + DOM.hide(this._viewport); + const spinner = DOM.$('div.loading-spinner.codicon.in-progress', { title: loadingText }); + this._loadingContainer.appendChild(spinner); + this._container.setAttribute('aria-busy', 'true'); + } + } else { + DOM.show(this._viewport); + DOM.clearNode(this._loadingContainer); + this._container.removeAttribute('aria-busy'); + } + this._loading = isLoading; + } +} diff --git a/src/sql/base/browser/ui/table/plugins/media/loadingSpinner.plugin.css b/src/sql/base/browser/ui/table/plugins/media/loadingSpinner.plugin.css new file mode 100644 index 0000000000..71abc088f8 --- /dev/null +++ b/src/sql/base/browser/ui/table/plugins/media/loadingSpinner.plugin.css @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.loading-spinner-plugin-container { + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +.loading-spinner-plugin-container .loading-spinner { + height: 30px; + margin-top: 5px; + margin-bottom: 5px; +} diff --git a/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts b/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts index 63759e5d8f..f5704ad5d8 100644 --- a/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts +++ b/src/sql/workbench/browser/editor/resourceViewer/resourceViewerInput.ts @@ -25,10 +25,13 @@ export class ResourceViewerInput extends EditorInput { public static ID: string = 'workbench.editorInput.resourceViewerInput'; private _data: azdata.DataGridItem[] = []; private _columns: ColumnDefinition[] = []; + private _loading: boolean = true; + + private _onLoadingChanged = new Emitter(); + public onLoadingChanged: Event = this._onLoadingChanged.event; private _onColumnsChanged = new Emitter[]>(); public actionsColumn: ButtonColumn; public onColumnsChanged: Event[]> = this._onColumnsChanged.event; - private _onDataChanged = new Emitter(); public onDataChanged: Event = this._onDataChanged.event; @@ -74,16 +77,24 @@ export class ResourceViewerInput extends EditorInput { } public async refresh(): Promise { + this._loading = true; + this._onLoadingChanged.fire(this._loading); await Promise.all([ this.fetchColumns(), this.fetchItems() ]); + this._loading = false; + this._onLoadingChanged.fire(this._loading); } public get plugins(): Slick.Plugin[] { return [this.actionsColumn]; } + public get loading(): boolean { + return this._loading; + } + private async fetchColumns(): Promise { const columns = await this._dataGridProviderService.getDataGridColumns(this._providerId); const columnDefinitions: ColumnDefinition[] = columns.map(col => { diff --git a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts index c4a21d233c..b4ace95680 100644 --- a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts +++ b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor.ts @@ -96,8 +96,6 @@ export class ResourceViewerEditor extends EditorPane { this._inputDisposables.clear(); - this._resourceViewerTable.data = input.data; - input.plugins.forEach(plugin => { this._resourceViewerTable.registerPlugin(plugin); this._inputDisposables.add({ @@ -107,17 +105,25 @@ export class ResourceViewerEditor extends EditorPane { }); }); - this._resourceViewerTable.columns = input.columns; this._inputDisposables.add(input.onColumnsChanged(columns => { this._resourceViewerTable.columns = columns; })); + this._resourceViewerTable.columns = input.columns; + this._inputDisposables.add(input.onDataChanged(() => { this._resourceViewerTable.data = input.data; })); + this._resourceViewerTable.data = input.data; + this._inputDisposables.add(input.actionsColumn.onClick(e => { this.showContextMenu(e.position, e.item); })); + this._inputDisposables.add(input.onLoadingChanged(loading => { + this._resourceViewerTable.loading = loading; + })); + this._resourceViewerTable.loading = input.loading; + this._actionBar.context = input; this._resourceViewerTable.focus(); diff --git a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts index ae7e0118a0..830d259a77 100644 --- a/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts +++ b/src/sql/workbench/contrib/resourceViewer/browser/resourceViewerTable.ts @@ -23,12 +23,13 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { ColumnDefinition } from 'sql/workbench/browser/editor/resourceViewer/resourceViewerInput'; import { Emitter } from 'vs/base/common/event'; import { ContextMenuAnchor } from 'sql/workbench/contrib/resourceViewer/browser/resourceViewerEditor'; +import { LoadingSpinnerPlugin } from 'sql/base/browser/ui/table/plugins/loadingSpinner.plugin'; export class ResourceViewerTable extends Disposable { private _resourceViewerTable!: Table; private _dataView: TableDataView; - + private _loadingSpinnerPlugin = new LoadingSpinnerPlugin(); private _onContextMenu = new Emitter<{ anchor: ContextMenuAnchor, item: azdata.DataGridItem }>(); public onContextMenu = this._onContextMenu.event; @@ -81,6 +82,7 @@ export class ResourceViewerTable extends Disposable { this._resourceViewerTable.grid.render(); }); this._resourceViewerTable.registerPlugin(filterPlugin); + this._resourceViewerTable.registerPlugin(this._loadingSpinnerPlugin); } public set data(data: azdata.DataGridItem[]) { @@ -94,6 +96,10 @@ export class ResourceViewerTable extends Disposable { this._resourceViewerTable.columns = columns; } + public set loading(isLoading: boolean) { + this._loadingSpinnerPlugin.loading = isLoading; + } + public registerPlugin(plugin: Slick.Plugin): void { this._resourceViewerTable.registerPlugin(plugin); }