From cb060cb5db464399fc2c1fe2b2e751f48d6dedea Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Thu, 5 Jul 2018 10:43:24 -0700 Subject: [PATCH] add row status on status bar for queries (#1841) --- src/sql/parts/query/common/rowCountStatus.ts | 92 +++++++++++++++++++ src/sql/parts/query/execution/queryModel.ts | 2 + .../query/execution/queryModelService.ts | 26 ++++-- 3 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 src/sql/parts/query/common/rowCountStatus.ts diff --git a/src/sql/parts/query/common/rowCountStatus.ts b/src/sql/parts/query/common/rowCountStatus.ts new file mode 100644 index 0000000000..cf13bf76f1 --- /dev/null +++ b/src/sql/parts/query/common/rowCountStatus.ts @@ -0,0 +1,92 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils'; +import { IQueryModelService } from '../execution/queryModel'; +import QueryRunner from 'sql/parts/query/execution/queryRunner'; + +import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorCloseEvent } from 'vs/workbench/common/editor'; +import { append, $, hide, show } from 'vs/base/browser/dom'; +import * as nls from 'vs/nls'; + +export class RowCountStatusBarItem implements IStatusbarItem { + + private _element: HTMLElement; + private _flavorElement: HTMLElement; + + private dispose: IDisposable; + + constructor( + @IWorkbenchEditorService private _editorService: IWorkbenchEditorService, + @IEditorGroupService private _editorGroupService: IEditorGroupService, + @IQueryModelService private _queryModelService: IQueryModelService + ) { } + + render(container: HTMLElement): IDisposable { + let disposables = [ + this._editorGroupService.onEditorsChanged(this._onEditorsChanged, this), + this._editorGroupService.getStacksModel().onEditorClosed(this._onEditorClosed, this) + ]; + + this._element = append(container, $('.query-statusbar-group')); + this._flavorElement = append(this._element, $('a.editor-status-selection')); + this._flavorElement.title = nls.localize('rowStatus', "Row Count"); + hide(this._flavorElement); + + this._showStatus(); + + return combinedDisposable(disposables); + } + + private _onEditorsChanged() { + this._showStatus(); + } + + private _onEditorClosed(event: IEditorCloseEvent) { + hide(this._flavorElement); + } + + // Show/hide query status for active editor + private _showStatus(): void { + hide(this._flavorElement); + dispose(this.dispose); + let activeEditor = this._editorService.getActiveEditor(); + if (activeEditor) { + let currentUri = WorkbenchUtils.getEditorUri(activeEditor.input); + if (currentUri) { + let queryRunner = this._queryModelService.getQueryRunner(currentUri); + if (queryRunner) { + if (queryRunner.hasCompleted) { + this._displayValue(queryRunner); + } else if (queryRunner.isExecuting) { + this.dispose = queryRunner.addListener('complete', () => { + this._displayValue(queryRunner); + }); + } + } else { + this.dispose = this._queryModelService.onRunQueryComplete(e => { + if (e === currentUri) { + this._displayValue(this._queryModelService.getQueryRunner(currentUri)); + } + }); + } + } + } + } + + private _displayValue(runner: QueryRunner) { + let number = runner.batchSets.reduce((p, c) => { + return p + c.resultSetSummaries.reduce((rp, rc) => { + return rp + rc.rowCount; + }, 0); + }, 0); + this._flavorElement.innerText = nls.localize('rowCount', "{0} rows", number); + show(this._flavorElement); + } +} diff --git a/src/sql/parts/query/execution/queryModel.ts b/src/sql/parts/query/execution/queryModel.ts index 17f45b83c2..7b1c04b148 100644 --- a/src/sql/parts/query/execution/queryModel.ts +++ b/src/sql/parts/query/execution/queryModel.ts @@ -30,6 +30,8 @@ export const IQueryModelService = createDecorator(SERVICE_ID export interface IQueryModelService { _serviceBrand: any; + getQueryRunner(uri: string): QueryRunner; + getConfig(): Promise<{ [key: string]: any }>; getShortcuts(): Promise; getQueryRows(uri: string, rowStart: number, numberOfRows: number, batchId: number, resultId: number): Thenable; diff --git a/src/sql/parts/query/execution/queryModelService.ts b/src/sql/parts/query/execution/queryModelService.ts index 9250ba134c..9611a6f32e 100644 --- a/src/sql/parts/query/execution/queryModelService.ts +++ b/src/sql/parts/query/execution/queryModelService.ts @@ -13,6 +13,7 @@ import { IQueryModelService } from 'sql/parts/query/execution/queryModel'; import { QueryInput } from 'sql/parts/query/common/queryInput'; import { QueryStatusbarItem } from 'sql/parts/query/execution/queryStatus'; import { SqlFlavorStatusbarItem } from 'sql/parts/query/common/flavorStatus'; +import { RowCountStatusBarItem } from 'sql/parts/query/common/rowCountStatus'; import * as sqlops from 'sqlops'; import { ISlickRange } from 'angular2-slickgrid'; @@ -85,6 +86,13 @@ export class QueryModelService implements IQueryModelService { this._onEditSessionReady = new Emitter(); // Register Statusbar items + + (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( + RowCountStatusBarItem, + statusbar.StatusbarAlignment.RIGHT, + 100 /* Should appear to the right of the SQL editor status */ + )); + (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( QueryStatusbarItem, statusbar.StatusbarAlignment.RIGHT, @@ -345,7 +353,7 @@ export class QueryModelService implements IQueryModelService { public disposeQuery(ownerUri: string): void { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { queryRunner.disposeQuery(); } @@ -437,7 +445,7 @@ export class QueryModelService implements IQueryModelService { public disposeEdit(ownerUri: string): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.disposeEdit(ownerUri); } @@ -446,7 +454,7 @@ export class QueryModelService implements IQueryModelService { public updateCell(ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.updateCell(ownerUri, rowId, columnId, newValue).then((result) => result, error => { this._notificationService.notify({ @@ -461,7 +469,7 @@ export class QueryModelService implements IQueryModelService { public commitEdit(ownerUri): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.commitEdit(ownerUri).then(() => { }, error => { this._notificationService.notify({ @@ -476,7 +484,7 @@ export class QueryModelService implements IQueryModelService { public createRow(ownerUri: string): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.createRow(ownerUri); } @@ -485,7 +493,7 @@ export class QueryModelService implements IQueryModelService { public deleteRow(ownerUri: string, rowId: number): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.deleteRow(ownerUri, rowId); } @@ -494,7 +502,7 @@ export class QueryModelService implements IQueryModelService { public revertCell(ownerUri: string, rowId: number, columnId: number): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.revertCell(ownerUri, rowId, columnId); } @@ -503,7 +511,7 @@ export class QueryModelService implements IQueryModelService { public revertRow(ownerUri: string, rowId: number): Thenable { // Get existing query runner - let queryRunner = this._getQueryRunner(ownerUri); + let queryRunner = this.getQueryRunner(ownerUri); if (queryRunner) { return queryRunner.revertRow(ownerUri, rowId); } @@ -512,7 +520,7 @@ export class QueryModelService implements IQueryModelService { // PRIVATE METHODS ////////////////////////////////////////////////////// - private _getQueryRunner(ownerUri): QueryRunner { + public getQueryRunner(ownerUri): QueryRunner { let queryRunner: QueryRunner = undefined; if (this._queryInfoMap.has(ownerUri)) { let existingRunner = this._getQueryInfo(ownerUri).queryRunner;