Skip to content

Commit

Permalink
Merge pull request #367 from komarovalexander/dev
Browse files Browse the repository at this point in the history
Header Filter improvements: Items customization & Item text customization & custom filter
  • Loading branch information
komarovalexander authored Dec 23, 2023
2 parents 49f2cea + cc497c8 commit 99916d7
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ module.exports = {
"no-caller": "error",
"no-cond-assign": "error",
"no-console": "off",
"no-debugger": "error",
"no-debugger": "warn",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-empty": "error",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ka-table",
"version": "8.6.0",
"version": "8.7.0",
"license": "MIT",
"repository": "github:komarovalexander/ka-table",
"homepage": "https://komarovalexander.github.io/ka-table/#/overview",
Expand Down
2 changes: 2 additions & 0 deletions src/Demos/Demos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import GroupingCustomRowDemo from './GroupingCustomRowDemo/GroupingCustomRowDemo
import GroupingDemo from './GroupingDemo/GroupingDemo';
import GroupingSummaryDemo from './GroupingSummaryDemo/GroupingSummaryDemo';
import HeaderFilterDemo from './HeaderFilterDemo/HeaderFilterDemo';
import HeaderFilterLogicDemo from './HeaderFilterLogicDemo/HeaderFilterLogicDemo';
import HoverRowDemo from './HoverRowDemo/HoverRowDemo';
import InfiniteScrollingDemo from './InfiniteScrollingDemo/InfiniteScrollingDemo';
import InsertRowDemo from './InsertRowDemo/InsertRowDemo';
Expand Down Expand Up @@ -113,6 +114,7 @@ const demos: Demo[] = [
new Demo(GroupingCustomRowDemo, '/grouping-custom-row', 'Grouping Custom Row', 'GroupingCustomRowDemo', 'https://stackblitz.com/edit/table-grouping-custom-row-js', 'https://stackblitz.com/edit/table-grouping-custom-row-ts', 'Grouping'),
new Demo(GroupingDemo, '/grouping', 'Grouping', 'GroupingDemo', 'https://stackblitz.com/edit/table-grouping-js', 'https://stackblitz.com/edit/table-grouping-ts', 'Grouping'),
new Demo(HeaderFilterDemo, '/header-filter', 'Header Filter', 'HeaderFilterDemo', 'https://stackblitz.com/edit/table-header-filter-js', 'https://stackblitz.com/edit/table-header-filter-ts', 'Filtering'),
new Demo(HeaderFilterLogicDemo, '/header-filter-logic', 'Header Filter - Logic', 'HeaderFilterLogicDemo', 'https://stackblitz.com/edit/table-header-filter-logic-js', 'https://stackblitz.com/edit/table-header-filter-logic-ts', 'Filtering'),
new Demo(GroupingSummaryDemo, '/grouping-summary', 'Grouping Summary', 'GroupingSummaryDemo', 'https://stackblitz.com/edit/table-grouping-summary-js', 'https://stackblitz.com/edit/table-grouping-summary-ts', 'Grouping'),
new Demo(HoverRowDemo, '/hover-row', 'Hover Row', 'HoverRowDemo', 'https://stackblitz.com/edit/table-hover-row-js', 'https://stackblitz.com/edit/table-hover-row-ts', 'Rows'),
new Demo(JsonDemo, '/json', 'Json', 'JsonDemo', 'https://stackblitz.com/edit/table-json-js', 'https://stackblitz.com/edit/table-json-ts', 'Remote Data'),
Expand Down
10 changes: 3 additions & 7 deletions src/Demos/FilterRowCustomLogicDemo/FilterRowCustomLogicDemo.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';

import { DataType, Table } from '../../lib';

import FilterRowNumber from '../../lib/Components/FilterRowNumber/FilterRowNumber';
import { FilteringMode } from '../../lib/enums';
import React from 'react';

const dataArray: any[] = [
{ id: 1, name: 'Mike Wazowski', score: 80, prevScores: [60, 65, 70], passed: true, nextTry: new Date(2021, 10, 9) },
Expand Down Expand Up @@ -42,6 +42,7 @@ const FilterRowCustomLogicDemo: React.FC = () => {
filterRowValue: 60,
key: 'prevScores',
style: {width: 120},
filter: (value: number[], filterRowValue: number) => value.includes(Number(filterRowValue)),
title: 'Previous Scores',
}
]}
Expand All @@ -51,11 +52,6 @@ const FilterRowCustomLogicDemo: React.FC = () => {
return value.join();
}
}}
filter= {({ column }) => {
if (column.key === 'prevScores') {
return (value: number[], filterRowValue: number) => value.includes(Number(filterRowValue));
}
}}
filteringMode={FilteringMode.FilterRow}
rowKeyField={'id'}
childComponents={{
Expand Down
10 changes: 10 additions & 0 deletions src/Demos/HeaderFilterLogicDemo/HeaderFilterLogicDemo.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import HeaderFilterLogicDemo from './HeaderFilterLogicDemo';
import React from 'react';
import { createRoot } from 'react-dom/client';

it('renders without crashing', () => {
const div = document.createElement('div');
const root = createRoot(div!);
root.render(<HeaderFilterLogicDemo />);
root.unmount();
});
115 changes: 115 additions & 0 deletions src/Demos/HeaderFilterLogicDemo/HeaderFilterLogicDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { DataType, Table } from '../../lib';
import { FilteringMode, SortDirection, SortingMode } from '../../lib/enums';

import React from 'react';

const dataArray: any[] = [
{
id: 1,
name: 'Mike Wazowski',
score: 80,
passed: true,
nextTry: new Date(2021, 10, 8),
departments: [{ name: 'Department A', id: 1 }, { name: 'Department B', id: 2 }]
},
{
id: 2,
name: 'Billi Bob',
score: 55,
passed: false,
nextTry: new Date(2021, 10, 8),
departments: [{ name: 'Department C', id: 3 }]
},
{
id: 3,
name: 'Tom Williams',
score: 55,
passed: false,
nextTry: new Date(2021, 11, 8),
departments: [{ name: 'Department A', id: 1 }]
},
{
id: 4,
name: 'Kurt Cobain',
score: 75,
passed: true,
nextTry: new Date(2021, 12, 9)
},
{
id: 5,
name: 'Marshall Bruce',
score: 77,
passed: true,
nextTry: new Date(2021, 11, 12)
},
{
id: 6,
name: 'Sunny Fox',
score: 33,
passed: false,
nextTry: new Date(2021, 10, 9)
},
];

const HeaderFilterLogicDemo = () => {
return (
<Table
columns={[
{
key: 'name',
title: 'Name', dataType: DataType.String,
sortDirection: SortDirection.Descend,
isFilterable: false
},
{
key: 'score',
title: 'Score', dataType: DataType.Number
},
{
key: 'passed',
title: 'Passed',
dataType: DataType.Boolean
},
{
key: 'nextTry',
dataType: DataType.Date,
title: 'Next Try',
},
{
key: 'departments',
dataType: DataType.Object,
title: 'Departments',
filter: (value: { name: string; id: number; }[], filterValues: { name: string; id: number; }[]) => {
return filterValues?.some(x => value?.some(v => v.id === x.id));
},
headerFilterListItems: ({ data }) => {
const departments: any[] | undefined = data?.reduce((acc, item) => [...acc, ...item.departments || []], []);
const departmentsUniqueByKey = departments?.filter((item: any, index) => {
return departments?.findIndex(i => i.id === item.id) === index;
});
return departmentsUniqueByKey || [];
}
},
]}
data={dataArray}
sortingMode={SortingMode.Single}
filteringMode={FilteringMode.HeaderFilter}
format={({ column, value }) => {
if (column.dataType === DataType.Date) {
return value && value.toLocaleDateString('en', { month: '2-digit', day: '2-digit', year: 'numeric' });
}
if (column.key === 'departments') {
return value?.map((d: any) => d.name).join(', ');
}
}}
childComponents={{
popupContentItemText: {
content: ({ item }) => item.name
}
}}
rowKeyField={'id'}
/>
);
};

export default HeaderFilterLogicDemo;
4 changes: 2 additions & 2 deletions src/Demos/MenuItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ export class MenuItem {
public isActive?: boolean;
}

const newItems: string[] = [];
const updateItems: string[] = ['GroupingDemo'];
const newItems: string[] = ['HeaderFilterLogicDemo'];
const updateItems: string[] = [];

const MenuItems: React.FC<{ items: MenuItem[] }> = ({ items }) => {

Expand Down
26 changes: 14 additions & 12 deletions src/lib/Components/PopupContent/PopupContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,25 @@ const PopupContent: React.FC<IPopupContentProps> = (props) => {
dispatch,
format
} = props;

let headerFilterValues = data?.map((item) => {
const value = getValueByColumn(item, column);

const formattedValue =
(format && format({ column, value, rowData: item }))
|| value?.toString();
return formattedValue;
});

headerFilterValues = Array.from(new Set(headerFilterValues));
let headerFilterValues: any[] | undefined;
if (column?.headerFilterListItems){
headerFilterValues = column?.headerFilterListItems({ data });
} else {
headerFilterValues = data?.map((item) => {
const value = getValueByColumn(item, column);

const formattedValue =
(format && format({ column, value, rowData: item }))
|| value?.toString();
return formattedValue;
});
headerFilterValues = Array.from(new Set(headerFilterValues));
}

const { elementAttributes, content } = getElementCustomization({
className: `${defaultOptions.css.popupContent}`
}, props, childComponents?.popupContent
);

return (
<div {...elementAttributes}>
{content ||
Expand Down
9 changes: 4 additions & 5 deletions src/lib/Components/PopupContentItem/PopupContentItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';

import { updateHeaderFilterValues } from '../../actionCreators';
import defaultOptions from '../../defaultOptions';
import { IPopupContentItemProps } from '../../props';
import PopupContentItemText from '../PopupContentItemText/PopupContentItemText';
import defaultOptions from '../../defaultOptions';
import { getElementCustomization } from '../../Utils/ComponentUtils';
import { updateHeaderFilterValues } from '../../actionCreators';

const PopupContentItem: React.FC<IPopupContentItemProps> = (props) => {
const {
Expand Down Expand Up @@ -35,9 +36,7 @@ const PopupContentItem: React.FC<IPopupContentItemProps> = (props) => {
onChange={handleChange}
/>
</div>
<div className='ka-popup-content-item-value'>
{item}
</div>
<PopupContentItemText {...props} />
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import PopupContentItemText from './PopupContentItemText';
import React from 'react';
import { createRoot } from 'react-dom/client';

const props: any = {
column: {key: 'field'},
childComponents: {},
dispatch: () => {},
item: ''
};

it('renders without crashing', () => {
const div = document.createElement('div');
const root = createRoot(div!);
root.render(<PopupContentItemText {...props} />);
root.unmount();
});
23 changes: 23 additions & 0 deletions src/lib/Components/PopupContentItemText/PopupContentItemText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as React from 'react';

import { IPopupContentItemProps } from '../../props';
import { getElementCustomization } from '../../Utils/ComponentUtils';

const PopupContentItemText: React.FC<IPopupContentItemProps> = (props) => {
const {
childComponents,
item
} = props;

const { elementAttributes, content } = getElementCustomization({
className: 'ka-popup-content-item-value'
}, props, childComponents?.popupContentItemText);

return (
<div {...elementAttributes}>
{content || item.toString()}
</div>
)
}

export default PopupContentItemText;
1 change: 1 addition & 0 deletions src/lib/Models/ChildComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class ChildComponents {
public pagingSizes?: ChildComponent<IPagingProps>;
public popupContent?: ChildComponent<IPopupContentProps>;
public popupContentItem?: ChildComponent<IPopupContentItemProps>;
public popupContentItemText?: ChildComponent<IPopupContentItemProps>;
public rootDiv?: ChildComponent<ITableProps>;
public sortIcon?: ChildComponent<ISortIconProps>;
public summaryCell?: ChildComponent<ISummaryCellProps>;
Expand Down
2 changes: 2 additions & 0 deletions src/lib/Models/Column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class Column {
public filterRowValue?: any;
public headerFilterValues?: any[];
public headerFilterPopupPosition?: PopupPosition;
public headerFilterListItems?: (props: { data?: any[] }) => any[];
public filter?: (value: any, filterValue: any, rowData?: any) => boolean;
public isHeaderFilterPopupShown?: boolean;
public isEditable?: boolean;
public isFilterable?: boolean;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/Utils/FilterUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ describe('FilterUtils', () => {
}];
expect(() => filterData(data, columns)).toThrowError('\'unknownOperator\' has not found in predefinedFilterOperators array, available operators: =, >, <, >=, <=, contains');
});

it('custom column filter', () => {
const columns = [{
dataType: DataType.Number,
filterRowValue: 45,
key: 'score',
filter: (value: any, filterValue: any) => value === filterValue,
}];
const result = filterData(data, columns);
expect(result).toMatchSnapshot();
});
});

[{
Expand Down
19 changes: 11 additions & 8 deletions src/lib/Utils/FilterUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const filterAndSearchData = (props: ITableProps) => {

const getCompare = (column: Column) => {
const filterRowOperator = column.filterRowOperator
|| getDefaultOperatorForType(column.dataType || defaultOptions.columnDataType);
|| getDefaultOperatorForType(column.dataType || defaultOptions.columnDataType);
const filterOperator = predefinedFilterOperators.find((fo) => filterRowOperator === fo.name);
if (!filterOperator) {
throw new Error(`'${column.filterRowOperator}' has not found in predefinedFilterOperators array, available operators: ${predefinedFilterOperators.map((o) => o.name).join(', ')}`);
Expand All @@ -71,12 +71,12 @@ export const filterData = (data: any[], columns: Column[], filter?: FilterFunc):
return columns.reduce((initialData, column) => {
if (
isEmpty(column.filterRowValue)
&& column.filterRowOperator !== FilterOperatorName.IsEmpty
&& column.filterRowOperator !== FilterOperatorName.IsNotEmpty
&& column.filterRowOperator !== FilterOperatorName.IsEmpty
&& column.filterRowOperator !== FilterOperatorName.IsNotEmpty
) {
return initialData;
}
const customFilter = filter?.({ column });
const customFilter = column.filter || filter?.({ column });
const compare = customFilter || getCompare(column);

return initialData.filter((d: any) => {
Expand Down Expand Up @@ -136,16 +136,19 @@ export const filterByHeaderFilter = (data: any[], columns: Column[], format?: Fo
return columns.reduce((initialData, column) => {
if (
isEmpty(column.headerFilterValues)
&& column.filterRowOperator !== FilterOperatorName.IsEmpty
&& column.filterRowOperator !== FilterOperatorName.IsNotEmpty
&& column.filterRowOperator !== FilterOperatorName.IsEmpty
&& column.filterRowOperator !== FilterOperatorName.IsNotEmpty
) {
return initialData;
}
return initialData.filter((item: any) => {
const value: any = getValueByColumn(item, column);
if (column?.filter) {
return column.filter(value, column.headerFilterValues, item);
}
const fieldValue =
(format && format({ column, value, rowData: item }))
|| value?.toString();
(format && format({ column, value, rowData: item }))
|| value?.toString();
return column.headerFilterValues?.includes(fieldValue);
});
}, data);
Expand Down
Loading

0 comments on commit 99916d7

Please sign in to comment.