From 9f761c44c4e6644ccdda6ef5c2b72a4cfa725e87 Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Thu, 5 Aug 2021 13:44:26 -0700 Subject: [PATCH] Add incremental grid loading option to notebooks (#16577) * render grids incrementally * add loading spinner * fix loading animation * move rendergrids to notebook editor component * add setting for incremental grid loading * check configuration * just use setTimeout to queue grids * remove extra line * add setter/getter for isloading * add comment --- .../notebook/browser/notebook.contribution.ts | 5 +++ .../browser/outputs/gridOutput.component.ts | 39 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts index 6d2b86e2c5..86359b82fc 100644 --- a/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/sql/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -340,6 +340,11 @@ configurationRegistry.registerConfiguration({ 'type': 'boolean', 'default': false, 'description': localize('notebook.useAbsoluteFilePaths', "Use absolute file paths when linking to other notebooks.") + }, + 'notebook.enableIncrementalGridRendering': { + 'type': 'boolean', + 'default': false, + 'description': localize('notebook.enableIncrementalGridRendering', "Enable incremental grid rendering for notebooks. This will improve the initial rendering time for large notebooks. There may be performance issues when interacting with the notebook while the rest of the grids are rendering.") } } }); diff --git a/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts b/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts index ba3b2954d2..320eac6846 100644 --- a/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { OnInit, Component, Input, Inject, ViewChild, ElementRef } from '@angular/core'; +import { OnInit, Component, Input, Inject, ViewChild, ElementRef, ChangeDetectorRef, forwardRef } from '@angular/core'; import * as azdata from 'azdata'; import { IGridDataProvider, getResultsString } from 'sql/workbench/services/query/common/gridDataProvider'; @@ -23,7 +23,7 @@ import { localize } from 'vs/nls'; import { IAction } from 'vs/base/common/actions'; import { AngularDisposable } from 'sql/base/browser/lifecycle'; import { IMimeComponent } from 'sql/workbench/contrib/notebook/browser/outputs/mimeRegistry'; -import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; +import { CellExecutionState, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces'; import { MimeModel } from 'sql/workbench/services/notebook/browser/outputs/mimemodel'; import { GridTableState } from 'sql/workbench/common/editor/query/gridTableState'; import { GridTableBase } from 'sql/workbench/contrib/query/browser/gridPanel'; @@ -51,7 +51,9 @@ import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; @Component({ selector: GridOutputComponent.SELECTOR, - template: `
` + template: ` + +
` }) export class GridOutputComponent extends AngularDisposable implements IMimeComponent, OnInit { public static readonly SELECTOR: string = 'grid-output'; @@ -66,12 +68,17 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo private _batchId: number | undefined; private _id: number | undefined; private _layoutCalledOnce: boolean = false; + private _incrementalGridRenderingEnabled: boolean; + private _isLoading: boolean = false; constructor( + @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, @Inject(IInstantiationService) private instantiationService: IInstantiationService, - @Inject(IThemeService) private readonly themeService: IThemeService + @Inject(IThemeService) private readonly themeService: IThemeService, + @Inject(IConfigurationService) private configurationService: IConfigurationService ) { super(); + this._incrementalGridRenderingEnabled = this.configurationService.getValue('notebook.enableIncrementalGridRendering'); } @Input() set bundleOptions(value: MimeModel.IOptions) { @@ -102,6 +109,17 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo this._cellOutput = value; } + get loading(): boolean { + return this._isLoading; + } + + @Input() set loading(isLoading: boolean) { + this._isLoading = isLoading; + if (!(this._changeRef['destroyed'])) { + this._changeRef.detectChanges(); + } + } + async ngOnInit() { if (this.cellModel) { let outputId: QueryResultId = this.cellModel.getOutputId(this._cellOutput); @@ -114,10 +132,21 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo this.updateResult(e.resultSet, e.rows); } })); + if (this._cellModel.executionState === CellExecutionState.Running || !this._incrementalGridRenderingEnabled) { + await this.renderGrid(); + } else { + this.loading = true; + // setTimeout adds the renderGrid call to a queue that gets called after all current tasks get executed - + // this allows the rest of the notebook to render first before rendering grids incrementally. + setTimeout(async () => { + await this.renderGrid(); + this.loading = false; + }); + } } - await this.renderGrid(); } + async renderGrid(): Promise { if (!this._bundleOptions || !this._cellModel || !this.mimeType) { return;