query results filtering and sorting (#14833)

* query results filtering and sorting (#14589)

* enable filter

* attach button style

* add hybrid data provider

* make filter and sort work

* fix editor switch issue

* configuration

* fix sort and filter

* add more specific selector

* fix hidden items issue

* update text

* revert text change

* fix copy results issue

* put feature behind preview flag

* comments

* fix tslint error
This commit is contained in:
Alan Ren
2021-03-23 11:30:41 -07:00
committed by GitHub
parent 5c67f3dbed
commit 6c54059f89
22 changed files with 554 additions and 132 deletions

View File

@@ -27,7 +27,7 @@ import { ICellModel } from 'sql/workbench/services/notebook/browser/models/model
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';
import { getErrorMessage } from 'vs/base/common/errors';
import { getErrorMessage, onUnexpectedError } from 'vs/base/common/errors';
import { ISerializationService, SerializeDataParams } from 'sql/platform/serialization/common/serializationService';
import { SaveResultAction, IGridActionContext } from 'sql/workbench/contrib/query/browser/actions';
import { SaveFormat, ResultSerializer, SaveResultsResponse } from 'sql/workbench/services/query/common/resultSerializer';
@@ -43,6 +43,7 @@ import { URI } from 'vs/base/common/uri';
import { assign } from 'vs/base/common/objects';
import { QueryResultId } from 'sql/workbench/services/notebook/browser/models/cell';
import { equals } from 'vs/base/common/arrays';
import { IDisposableDataProvider } from 'sql/base/common/dataProvider';
@Component({
selector: GridOutputComponent.SELECTOR,
template: `<div #output class="notebook-cellTable"></div>`
@@ -71,7 +72,7 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo
@Input() set bundleOptions(value: MimeModel.IOptions) {
this._bundleOptions = value;
if (this._initialized) {
this.renderGrid();
this.renderGrid().catch(onUnexpectedError);
}
}
@@ -84,7 +85,7 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo
@Input() set cellModel(value: ICellModel) {
this._cellModel = value;
if (this._initialized) {
this.renderGrid();
this.renderGrid().catch(onUnexpectedError);
}
}
@@ -96,7 +97,7 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo
this._cellOutput = value;
}
ngOnInit() {
async ngOnInit() {
if (this.cellModel) {
let outputId: QueryResultId = this.cellModel.getOutputId(this._cellOutput);
if (outputId) {
@@ -109,10 +110,10 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo
}
}));
}
this.renderGrid();
await this.renderGrid();
}
renderGrid(): void {
async renderGrid(): Promise<void> {
if (!this._bundleOptions || !this._cellModel || !this.mimeType) {
return;
}
@@ -124,7 +125,7 @@ export class GridOutputComponent extends AngularDisposable implements IMimeCompo
let outputElement = <HTMLElement>this.output.nativeElement;
outputElement.appendChild(this._table.element);
this._register(attachTableStyler(this._table, this.themeService));
this._table.onDidInsert();
await this._table.onDidInsert();
this.layout();
this._initialized = true;
}
@@ -200,9 +201,13 @@ class DataResourceTable extends GridTableBase<any> {
@IEditorService editorService: IEditorService,
@IUntitledTextEditorService untitledEditorService: IUntitledTextEditorService,
@IConfigurationService configurationService: IConfigurationService,
@IQueryModelService queryModelService: IQueryModelService
@IQueryModelService queryModelService: IQueryModelService,
@IThemeService themeService: IThemeService
) {
super(state, createResultSet(source), { actionOrientation: ActionsOrientation.HORIZONTAL }, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService);
super(state, createResultSet(source), {
actionOrientation: ActionsOrientation.HORIZONTAL,
inMemoryDataProcessing: true
}, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService, themeService);
this._gridDataProvider = this.instantiationService.createInstance(DataResourceDataProvider, source, this.resultSet, this.cellModel);
this._chart = this.instantiationService.createInstance(ChartView, false);
@@ -352,13 +357,13 @@ export class DataResourceDataProvider implements IGridDataProvider {
return Promise.resolve(resultSubset);
}
async copyResults(selection: Slick.Range[], includeHeaders?: boolean): Promise<void> {
return this.copyResultsAsync(selection, includeHeaders);
async copyResults(selection: Slick.Range[], includeHeaders?: boolean, tableView?: IDisposableDataProvider<Slick.SlickData>): Promise<void> {
return this.copyResultsAsync(selection, includeHeaders, tableView);
}
private async copyResultsAsync(selection: Slick.Range[], includeHeaders?: boolean): Promise<void> {
private async copyResultsAsync(selection: Slick.Range[], includeHeaders?: boolean, tableView?: IDisposableDataProvider<Slick.SlickData>): Promise<void> {
try {
let results = await getResultsString(this, selection, includeHeaders);
let results = await getResultsString(this, selection, includeHeaders, tableView);
this._clipboardService.writeText(results);
} catch (error) {
this._notificationService.error(localize('copyFailed', "Copy failed with error {0}", getErrorMessage(error)));