handling array as a table data and headerFilter.plugin (#12926)

This commit is contained in:
Vladimir Chernov
2020-10-15 19:20:59 +03:00
committed by GitHub
parent 52e7bcdf09
commit a88669677f
4 changed files with 103 additions and 38 deletions

View File

@@ -756,4 +756,11 @@ declare module 'azdata' {
*/
title: string;
}
export interface TableComponentProperties {
/**
* Specifies whether to use headerFilter plugin
*/
headerFilter?: boolean,
}
}

View File

@@ -94,6 +94,9 @@ export function slickGridDataItemColumnValueWithNoData(value: any, columnDef: an
if (typeof displayValue === 'number') {
displayValue = displayValue.toString();
}
if (displayValue instanceof Array) {
displayValue = displayValue.toString();
}
return {
text: displayValue,
ariaLabel: displayValue ? escape(displayValue) : ((displayValue !== undefined) ? localize("tableCell.NoDataAvailable", "no data available") : displayValue)

View File

@@ -15,9 +15,9 @@ export interface IExtendedColumn<T> extends Slick.Column<T> {
}
export interface CommandEventArgs<T extends Slick.SlickData> {
grid: Slick.Grid<T>,
column: Slick.Column<T>,
command: string
grid: Slick.Grid<T>,
column: Slick.Column<T>,
command: string
}
export class HeaderFilter<T extends Slick.SlickData> {
@@ -337,55 +337,50 @@ export class HeaderFilter<T extends Slick.SlickData> {
}
private getFilterValues(dataView: Slick.DataProvider<T>, column: Slick.Column<T>): Array<any> {
const seen: Array<string> = [];
for (let i = 0; i < dataView.getLength(); i++) {
const value = dataView.getItem(i)[column.field!];
const seen: Set<string> = new Set();
dataView.getItems().forEach(items => {
const value = items[column.field!];
const valueArr = value instanceof Array ? value : [value];
valueArr.forEach(v => seen.add(v));
});
if (!seen.some(x => x === value)) {
seen.push(value);
}
}
return seen;
return Array.from(seen);
}
private getFilterValuesByInput($input: JQuery<HTMLElement>): Array<string> {
const column = $input.data('column'),
filter = $input.val() as string,
dataView = this.grid.getData() as Slick.DataProvider<T>,
seen: Array<any> = [];
for (let i = 0; i < dataView.getLength(); i++) {
const value = dataView.getItem(i)[column.field];
seen: Set<any> = new Set();
dataView.getItems().forEach(item => {
const value = item[column.field];
const valueArr = value instanceof Array ? value : [(!value ? '' : value)];
if (filter.length > 0) {
const itemValue = !value ? '' : value;
const lowercaseFilter = filter.toString().toLowerCase();
const lowercaseVal = itemValue.toString().toLowerCase();
if (!seen.some(x => x === value) && lowercaseVal.indexOf(lowercaseFilter) > -1) {
seen.push(value);
}
valueArr.map(v => v.toLowerCase()).forEach((lowerVal, index) => {
if (lowerVal.indexOf(lowercaseFilter) > -1) {
seen.add(valueArr[index]);
}
});
} else {
valueArr.forEach(v => seen.add(v));
}
else {
if (!seen.some(x => x === value)) {
seen.push(value);
}
}
}
});
return seen.sort((v) => { return v; });
return Array.from(seen).sort((v) => { return v; });
}
private getAllFilterValues(data: Array<Slick.SlickData>, column: Slick.Column<T>) {
const seen: Array<any> = [];
for (let i = 0; i < data.length; i++) {
const value = data[i][column.field!];
const seen: Set<any> = new Set();
if (!seen.some(x => x === value)) {
seen.push(value);
}
}
data.forEach(items => {
const value = items[column.field!];
const valueArr = value instanceof Array ? value : [value];
valueArr.forEach(v => seen.add(v));
});
return seen.sort((v) => { return v; });
return Array.from(seen).sort((v) => { return v; });
}
private handleMenuItemClick(e: JQuery.Event<HTMLElement, null>, command: string, columnDef: Slick.Column<T>) {

View File

@@ -15,7 +15,7 @@ import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBa
import { Table } from 'sql/base/browser/ui/table/table';
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
import { attachTableStyler } from 'sql/platform/theme/common/styler';
import { attachTableStyler, attachButtonStyler } from 'sql/platform/theme/common/styler';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { getContentHeight, getContentWidth, Dimension } from 'vs/base/browser/dom';
import { RowSelectionModel } from 'sql/base/browser/ui/table/plugins/rowSelectionModel.plugin';
@@ -29,6 +29,7 @@ import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } fro
import { convertSizeToNumber } from 'sql/base/browser/dom';
import { ButtonColumn, ButtonClickEventArgs } from 'sql/base/browser/ui/table/plugins/buttonColumn.plugin';
import { createIconCssClass } from 'sql/workbench/browser/modelComponents/iconUtils';
import { HeaderFilter } from 'sql/base/browser/ui/table/plugins/headerFilter.plugin';
export enum ColumnSizingMode {
ForceFit = 0, // all columns will be sized to fit in viewable space, no horiz scroll bar
@@ -51,6 +52,7 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
private _checkboxColumns: CheckboxSelectColumn<{}>[] = [];
private _buttonsColumns: ButtonColumn<{}>[] = [];
private _pluginsRegisterStatus: boolean[] = [];
private _filterPlugin: HeaderFilter<Slick.SlickData>;
private _onCheckBoxChanged = new Emitter<ICheckboxCellActionEventArgs>();
private _onButtonClicked = new Emitter<ButtonClickEventArgs<{}>>();
public readonly onCheckBoxChanged: vsEvent<ICheckboxCellActionEventArgs> = this._onCheckBoxChanged.event;
@@ -133,7 +135,30 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
ngAfterViewInit(): void {
if (this._inputContainer) {
this._tableData = new TableDataView<Slick.SlickData>();
this._tableData = new TableDataView<Slick.SlickData>(
null,
null,
null,
(data: Slick.SlickData[]) => {
let columns = this._table.grid.getColumns();
for (let i = 0; i < columns.length; i++) {
let col: any = columns[i];
let filterValues: Array<any> = col.filterValues;
if (filterValues && filterValues.length > 0) {
return data.filter(item => {
let colValue = item[col.field];
if (colValue instanceof Array) {
return filterValues.find(x => colValue.indexOf(x) >= 0);
}
return filterValues.find(x => x === colValue);
});
}
}
return data;
}
);
let options = <Slick.GridOptions<any>>{
syncColumnCellResize: true,
@@ -249,7 +274,9 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
Object.keys(this._checkboxColumns).forEach(col => this.registerPlugins(col, this._checkboxColumns[col]));
Object.keys(this._buttonsColumns).forEach(col => this.registerPlugins(col, this._buttonsColumns[col]));
if (this.headerFilter === true) {
this.registerFilterPlugin();
}
if (this.ariaRowCount === -1) {
this._table.removeAriaRowCount();
}
@@ -356,6 +383,35 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
}
private registerFilterPlugin() {
const filterPlugin = new HeaderFilter<Slick.SlickData>();
this._register(attachButtonStyler(filterPlugin, this.themeService));
this._filterPlugin = filterPlugin;
this._filterPlugin.onFilterApplied.subscribe((e, args) => {
let filterValues = (<any>args).column.filterValues;
if (filterValues) {
this._tableData.filter();
this._table.grid.resetActiveCell();
this.layoutTable();
} else {
this._tableData.clearFilter();
}
});
this._filterPlugin.onCommand.subscribe((e, args: any) => {
this._tableData.sort({
sortAsc: args.command === 'sort-asc',
sortCol: args.column,
multiColumnSort: false,
grid: this._table.grid
});
this.layoutTable();
});
this._table.registerPlugin(filterPlugin);
}
public focus(): void {
if (this._table.grid.getDataLength() > 0) {
if (!this._table.grid.getActiveCell()) {
@@ -426,4 +482,8 @@ export default class TableComponent extends ComponentBase<azdata.TableComponentP
public set updateCells(newValue: azdata.TableCell[]) {
this.setPropertyFromUI<azdata.TableCell[]>((properties, value) => { properties.updateCells = value; }, newValue);
}
public get headerFilter(): boolean {
return this.getPropertyOrDefault<boolean>((props) => props.headerFilter, false);
}
}