diff --git a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts index 6d9652cbb6..915de5daeb 100644 --- a/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/headerFilter.plugin.ts @@ -29,15 +29,27 @@ export interface CommandEventArgs { command: HeaderFilterCommands } +export interface ITableFilterOptions { + /** + * The message to be displayed when the filter is disabled and the user tries to open the filter menu. + */ + disabledFilterMessage?: string; +} + export interface ITableFilterStyles extends IButtonStyles, IInputBoxStyles, IListStyles, ICountBadgetyles { } +interface NotificationProvider { + info(message: string): void; +} + const ShowFilterText: string = localize('headerFilter.showFilter', "Show Filter"); export class HeaderFilter { public onFilterApplied = new Slick.Event<{ grid: Slick.Grid, column: FilterableColumn }>(); public onCommand = new Slick.Event>(); + public enabled: boolean = true; private grid!: Slick.Grid; private handler = new Slick.EventHandler(); @@ -59,11 +71,10 @@ export class HeaderFilter { private columnDef!: FilterableColumn; private filterStyles?: ITableFilterStyles; private disposableStore = new DisposableStore(); - private _enabled: boolean = true; private columnButtonMapping: Map = new Map(); private previouslyFocusedElement: HTMLElement; - constructor(private readonly contextViewProvider: IContextViewProvider) { + constructor(private readonly contextViewProvider: IContextViewProvider, private readonly notificationProvider?: NotificationProvider, private readonly options?: ITableFilterOptions) { } public init(grid: Slick.Grid): void { @@ -104,7 +115,7 @@ export class HeaderFilter { const cell = this.grid.getActiveCell(); if (cell) { const column = this.grid.getColumns()[cell.cell] as FilterableColumn; - if (column.filterable !== false && this.enabled && this.columnButtonMapping[column.id]) { + if (column.filterable !== false && this.columnButtonMapping[column.id]) { await this.showFilter(this.columnButtonMapping[column.id]); EventHelper.stop(e, true); } @@ -123,9 +134,6 @@ export class HeaderFilter { } private handleHeaderCellRendered(e: Event, args: Slick.OnHeaderCellRenderedEventArgs) { - if (!this.enabled) { - return; - } const column = args.column as FilterableColumn; if ((>column).filterable === false) { return; @@ -305,6 +313,12 @@ export class HeaderFilter { } private async showFilter(filterButton: HTMLElement): Promise { + if (!this.enabled) { + if (this.notificationProvider && this.options?.disabledFilterMessage) { + this.notificationProvider.info(this.options.disabledFilterMessage); + } + return; + } this.previouslyFocusedElement = document.activeElement as HTMLElement; await this.createFilterMenu(filterButton); // Get the absolute coordinates of the filter button @@ -482,20 +496,6 @@ export class HeaderFilter { command: command }); } - - public get enabled(): boolean { - return this._enabled; - } - - public set enabled(value: boolean) { - if (this._enabled !== value) { - this._enabled = value; - // force the table header to redraw. - this.grid.getColumns().forEach((column) => { - this.grid.updateColumnHeader(column.id); - }); - } - } } class TableFilterListElement { 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 21049aaac2..633f619294 100644 --- a/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts +++ b/src/sql/workbench/contrib/notebook/browser/outputs/gridOutput.component.ts @@ -208,12 +208,13 @@ class DataResourceTable extends GridTableBase { @IConfigurationService configurationService: IConfigurationService, @IQueryModelService queryModelService: IQueryModelService, @IThemeService themeService: IThemeService, - @IContextViewService contextViewService: IContextViewService + @IContextViewService contextViewService: IContextViewService, + @INotificationService notificationService: INotificationService ) { super(state, createResultSet(source), { actionOrientation: ActionsOrientation.HORIZONTAL, inMemoryDataProcessing: true - }, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService, themeService, contextViewService); + }, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService, themeService, contextViewService, notificationService); this._gridDataProvider = this.instantiationService.createInstance(DataResourceDataProvider, source, this.resultSet, this.cellModel); this._chart = this.instantiationService.createInstance(ChartView, false); diff --git a/src/sql/workbench/contrib/query/browser/gridPanel.ts b/src/sql/workbench/contrib/query/browser/gridPanel.ts index 99b8130012..c51f30b8ff 100644 --- a/src/sql/workbench/contrib/query/browser/gridPanel.ts +++ b/src/sql/workbench/contrib/query/browser/gridPanel.ts @@ -51,6 +51,7 @@ import { Orientation } from 'vs/base/browser/ui/splitview/splitview'; import { IQueryModelService } from 'sql/workbench/services/query/common/queryModel'; import { HeaderFilter } from 'sql/base/browser/ui/table/plugins/headerFilter.plugin'; import { HybridDataProvider } from 'sql/base/browser/ui/table/hybridDataProvider'; +import { INotificationService } from 'vs/platform/notification/common/notification'; const ROW_HEIGHT = 29; const HEADER_HEIGHT = 26; @@ -385,7 +386,8 @@ export abstract class GridTableBase extends Disposable implements IView { @IConfigurationService protected readonly configurationService: IConfigurationService, @IQueryModelService private readonly queryModelService: IQueryModelService, @IThemeService private readonly themeService: IThemeService, - @IContextViewService private readonly contextViewService: IContextViewService + @IContextViewService private readonly contextViewService: IContextViewService, + @INotificationService private readonly notificationService: INotificationService ) { super(); let config = this.configurationService.getValue<{ rowHeight: number }>('resultsGrid'); @@ -527,7 +529,9 @@ export abstract class GridTableBase extends Disposable implements IView { this.table.rerenderGrid(); })); if (this.enableFilteringFeature) { - this.filterPlugin = new HeaderFilter(this.contextViewService); + this.filterPlugin = new HeaderFilter(this.contextViewService, this.notificationService, { + disabledFilterMessage: localize('resultsGrid.maxRowCountExceeded', "Max row count for filtering/sorting has been exceeded. To update it, you can go to User Settings and change the setting: 'queryEditor.results.inMemoryDataProcessingThreshold'") + }); this._register(attachTableFilterStyler(this.filterPlugin, this.themeService)); this.table.registerPlugin(this.filterPlugin); } @@ -871,13 +875,14 @@ class GridTable extends GridTableBase { @IConfigurationService configurationService: IConfigurationService, @IQueryModelService queryModelService: IQueryModelService, @IThemeService themeService: IThemeService, - @IContextViewService contextViewService: IContextViewService + @IContextViewService contextViewService: IContextViewService, + @INotificationService notificationService: INotificationService ) { super(state, resultSet, { actionOrientation: ActionsOrientation.VERTICAL, inMemoryDataProcessing: true, inMemoryDataCountThreshold: configurationService.getValue('queryEditor').results.inMemoryDataProcessingThreshold, - }, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService, themeService, contextViewService); + }, contextMenuService, instantiationService, editorService, untitledEditorService, configurationService, queryModelService, themeService, contextViewService, notificationService); this._gridDataProvider = this.instantiationService.createInstance(QueryGridDataProvider, this._runner, resultSet.batchId, resultSet.id); } diff --git a/src/sql/workbench/contrib/query/browser/query.contribution.ts b/src/sql/workbench/contrib/query/browser/query.contribution.ts index d134b99781..333648750f 100644 --- a/src/sql/workbench/contrib/query/browser/query.contribution.ts +++ b/src/sql/workbench/contrib/query/browser/query.contribution.ts @@ -394,7 +394,7 @@ const queryEditorConfiguration: IConfigurationNode = { 'queryEditor.results.inMemoryDataProcessingThreshold': { 'type': 'number', 'default': 5000, - 'description': localize('queryEditor.inMemoryDataProcessingThreshold', "Controls the max number of rows allowed to do filtering and sorting in memory. If the number is exceeded, sorting and filtering will be disabled.") + 'description': localize('queryEditor.inMemoryDataProcessingThreshold', "Controls the max number of rows allowed to do filtering and sorting in memory. If the number is exceeded, sorting and filtering will be disabled. Warning: Increasing this may impact performance.") }, 'queryEditor.messages.showBatchTime': { 'type': 'boolean',