diff --git a/src/sql/workbench/contrib/query/browser/gridPanel.ts b/src/sql/workbench/contrib/query/browser/gridPanel.ts index 1085adc10e..99b8130012 100644 --- a/src/sql/workbench/contrib/query/browser/gridPanel.ts +++ b/src/sql/workbench/contrib/query/browser/gridPanel.ts @@ -654,17 +654,25 @@ export abstract class GridTableBase extends Disposable implements IView { } private async notifyTableSelectionChanged() { - const selectedValues = []; + const selectedCells = []; for (const range of this.state.selection) { - const subset = await this.gridDataProvider.getRowData(range.fromRow, range.toRow - range.fromRow + 1); - subset.rows.forEach(row => { + let subset; + if (this.dataProvider.isDataInMemory) { + // handle the scenario when the data is sorted/filtered, + // we need to use the data that is being displayed + const data = await this.dataProvider.getRangeAsync(range.fromRow, range.toRow - range.fromRow + 1); + subset = data.map(item => Object.keys(item).map(key => item[key])); + } else { + subset = (await this.gridDataProvider.getRowData(range.fromRow, range.toRow - range.fromRow + 1)).rows; + } + subset.forEach(row => { // start with range.fromCell -1 because we have row number column which is not available in the actual data for (let i = range.fromCell - 1; i < range.toCell; i++) { - selectedValues.push(row[i]?.displayValue); + selectedCells.push(row[i]); } }); } - this.queryModelService.notifyCellSelectionChanged(selectedValues); + this.queryModelService.notifyCellSelectionChanged(selectedCells); } private onTableClick(event: ITableMouseEvent) { @@ -761,7 +769,8 @@ export abstract class GridTableBase extends Disposable implements IView { dataWithSchema[this.columns[i].field] = { displayValue: r[i - 1].displayValue, ariaLabel: escape(r[i - 1].displayValue), - isNull: r[i - 1].isNull + isNull: r[i - 1].isNull, + invariantCultureDisplayValue: r[i - 1].invariantCultureDisplayValue }; } return dataWithSchema as T; diff --git a/src/sql/workbench/contrib/query/browser/statusBarItems.ts b/src/sql/workbench/contrib/query/browser/statusBarItems.ts index 18e5944a09..8d0bce09a8 100644 --- a/src/sql/workbench/contrib/query/browser/statusBarItems.ts +++ b/src/sql/workbench/contrib/query/browser/statusBarItems.ts @@ -6,6 +6,7 @@ import { parseNumAsTimeString } from 'sql/platform/connection/common/utils'; import { QueryEditorInput } from 'sql/workbench/common/editor/query/queryEditorInput'; import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService'; +import { ICellValue } from 'sql/workbench/services/query/common/query'; import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel'; import QueryRunner from 'sql/workbench/services/query/common/queryRunner'; import { IntervalTimer } from 'vs/base/common/async'; @@ -277,8 +278,8 @@ export class QueryResultSelectionSummaryStatusBarContribution extends Disposable this._register(editorService.onDidActiveEditorChange(() => { this.hide(); }, this)); this._register(queryModelService.onRunQueryStart(() => { this.hide(); })); this._register(notebookService.onCodeCellExecutionStart(() => { this.hide(); })); - this._register(queryModelService.onCellSelectionChanged((data: string[]) => { - this.onCellSelectionChanged(data); + this._register(queryModelService.onCellSelectionChanged((selectedCells: ICellValue[]) => { + this.onCellSelectionChanged(selectedCells); })); } @@ -290,15 +291,15 @@ export class QueryResultSelectionSummaryStatusBarContribution extends Disposable this.statusbarService.updateEntryVisibility(QueryResultSelectionSummaryStatusBarContribution.ID, true); } - private onCellSelectionChanged(data: string[]): void { - const numericValues = data?.filter(value => !Number.isNaN(Number(value))).map(value => Number(value)); + private onCellSelectionChanged(selectedCells: ICellValue[]): void { + const numericValues = selectedCells?.map(cell => cell.invariantCultureDisplayValue || cell.displayValue).filter(value => !Number.isNaN(Number(value))).map(value => Number(value)); if (numericValues?.length < 2) { this.hide(); return; } const sum = numericValues.reduce((previous, current, idx, array) => previous + current); - const summaryText = localize('status.query.summaryText', "Average: {0} Count: {1} Sum: {2}", Number((sum / numericValues.length).toFixed(3)), data.length, sum); + const summaryText = localize('status.query.summaryText', "Average: {0} Count: {1} Sum: {2}", Number((sum / numericValues.length).toFixed(3)), selectedCells.length, sum); this.statusItem.update({ text: summaryText, ariaLabel: summaryText diff --git a/src/sql/workbench/services/query/common/query.ts b/src/sql/workbench/services/query/common/query.ts index edeab42d45..d036874e91 100644 --- a/src/sql/workbench/services/query/common/query.ts +++ b/src/sql/workbench/services/query/common/query.ts @@ -73,4 +73,5 @@ export interface ResultSetSubset { export interface ICellValue { displayValue: string; isNull?: boolean; + invariantCultureDisplayValue?: string; } diff --git a/src/sql/workbench/services/query/common/queryModel.ts b/src/sql/workbench/services/query/common/queryModel.ts index 9e239df8c4..b557425ad2 100644 --- a/src/sql/workbench/services/query/common/queryModel.ts +++ b/src/sql/workbench/services/query/common/queryModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import QueryRunner from 'sql/workbench/services/query/common/queryRunner'; -import { IQueryMessage, ResultSetSubset } from 'sql/workbench/services/query/common/query'; +import { ICellValue, IQueryMessage, ResultSetSubset } from 'sql/workbench/services/query/common/query'; import { DataService } from 'sql/workbench/services/query/common/dataService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; @@ -48,8 +48,8 @@ export interface IQueryEvent { export interface IQueryModelService { _serviceBrand: undefined; - onCellSelectionChanged: Event; - notifyCellSelectionChanged(selectedValues: string[]): void; + onCellSelectionChanged: Event; + notifyCellSelectionChanged(selectedValues: ICellValue[]): void; getQueryRunner(uri: string): QueryRunner | undefined; diff --git a/src/sql/workbench/services/query/common/queryModelService.ts b/src/sql/workbench/services/query/common/queryModelService.ts index b6cbdd52c3..329ddc7e8c 100644 --- a/src/sql/workbench/services/query/common/queryModelService.ts +++ b/src/sql/workbench/services/query/common/queryModelService.ts @@ -5,7 +5,7 @@ import * as GridContentEvents from 'sql/workbench/services/query/common/gridContentEvents'; import QueryRunner from 'sql/workbench/services/query/common/queryRunner'; -import { ResultSetSubset } from 'sql/workbench/services/query/common/query'; +import { ICellValue, ResultSetSubset } from 'sql/workbench/services/query/common/query'; import { DataService } from 'sql/workbench/services/query/common/dataService'; import { IQueryModelService, IQueryEvent } from 'sql/workbench/services/query/common/queryModel'; @@ -62,7 +62,7 @@ export class QueryModelService implements IQueryModelService { private _onRunQueryComplete: Emitter; private _onQueryEvent: Emitter; private _onEditSessionReady: Emitter; - private _onCellSelectionChangedEmitter = new Emitter(); + private _onCellSelectionChangedEmitter = new Emitter(); // EVENTS ///////////////////////////////////////////////////////////// public get onRunQueryStart(): Event { return this._onRunQueryStart.event; } @@ -70,7 +70,7 @@ export class QueryModelService implements IQueryModelService { public get onRunQueryComplete(): Event { return this._onRunQueryComplete.event; } public get onQueryEvent(): Event { return this._onQueryEvent.event; } public get onEditSessionReady(): Event { return this._onEditSessionReady.event; } - public get onCellSelectionChanged(): Event { return this._onCellSelectionChangedEmitter.event; } + public get onCellSelectionChanged(): Event { return this._onCellSelectionChangedEmitter.event; } // CONSTRUCTOR ///////////////////////////////////////////////////////// constructor( @@ -100,10 +100,10 @@ export class QueryModelService implements IQueryModelService { /** * Notify the event subscribers about the new selected cell values - * @param selectedValues current selected cell values + * @param selectedCells current selected cells */ - public notifyCellSelectionChanged(selectedValues: string[]): void { - this._onCellSelectionChangedEmitter.fire(selectedValues); + public notifyCellSelectionChanged(selectedCells: ICellValue[]): void { + this._onCellSelectionChangedEmitter.fire(selectedCells); } /** diff --git a/src/sql/workbench/services/query/test/common/testQueryModelService.ts b/src/sql/workbench/services/query/test/common/testQueryModelService.ts index 73ae99cbb6..73fbd181b0 100644 --- a/src/sql/workbench/services/query/test/common/testQueryModelService.ts +++ b/src/sql/workbench/services/query/test/common/testQueryModelService.ts @@ -10,12 +10,12 @@ import { Event } from 'vs/base/common/event'; import { QueryInfo } from 'sql/workbench/services/query/common/queryModelService'; import { DataService } from 'sql/workbench/services/query/common/dataService'; import { IRange } from 'vs/editor/common/core/range'; - +import { ICellValue } from 'sql/workbench/services/query/common/query'; export class TestQueryModelService implements IQueryModelService { _serviceBrand: any; onRunQueryUpdate: Event; - onCellSelectionChanged: Event; - notifyCellSelectionChanged(selectedValues: string[]): void { + onCellSelectionChanged: Event; + notifyCellSelectionChanged(selectedCells: ICellValue[]): void { throw new Error('Method not implemented.'); } getQueryRunner(uri: string): QueryRunner {