Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,108 @@ test('The item\'s selection state should be correct if a custom data source is s
],
});
});

test('The item\'s selection state should be correct after search', async (t) => {
// arrange
const cardView = new CardView('#container');

await t
.click(cardView.getHeaderPanel().getHeaderItem(0).getFilterIcon());

const headerFilterList = cardView.getHeaderFilterList();

// assert
await t
.expect(headerFilterList.getItems().count)
.eql(4);

const firstHeaderFilterItem = headerFilterList.getItem(0);

// act
await t
.click(firstHeaderFilterItem.element);

// assert
await t
.expect(firstHeaderFilterItem.isSelected)
.ok();

// act
await t
.typeText(headerFilterList.searchInput, '1');

// assert
await t
.expect(headerFilterList.getItems().count)
.eql(1)
.expect(headerFilterList.getItem(0).isSelected)
.ok();
}).before(async () => {
await createWidget('dxCardView', {
...baseConfig,
headerFilter: {
visible: true,
search: {
enabled: true,
},
},
});
});

test('The item\'s selection state should be correct after resetting the search', async (t) => {
// arrange
const cardView = new CardView('#container');

await t
.click(cardView.getHeaderPanel().getHeaderItem(0).getFilterIcon());

const headerFilterList = cardView.getHeaderFilterList();

// assert
await t
.expect(headerFilterList.getItems().count)
.eql(4);

// act
await t
.typeText(headerFilterList.searchInput, '1');

// assert
await t
.expect(headerFilterList.getItems().count)
.eql(1);

const firstHeaderFilterItem = headerFilterList.getItem(0);

// act
await t
.click(firstHeaderFilterItem.element);

// assert
await t
.expect(firstHeaderFilterItem.isSelected)
.ok();

// act
await t
.click(headerFilterList.searchInput)
.selectText(headerFilterList.searchInput)
.pressKey('backspace');

// assert
await t
.expect(headerFilterList.getItems().count)
.eql(4)
.expect(headerFilterList.getItem(0).isSelected)
.ok();
}).before(async () => {
await createWidget('dxCardView', {
...baseConfig,
headerFilter: {
visible: true,
search: {
enabled: true,
},
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { updateHeaderFilterItemSelectionState } from '@ts/grids/grid_core/header
import gridCoreUtils from '@ts/grids/grid_core/m_utils';
import type { Column } from '@ts/grids/new/grid_core/columns_controller/types';

import type { HeaderFilterListType } from './types';

export const getHeaderItemText = (
displayValue,
column,
Expand Down Expand Up @@ -137,10 +139,12 @@ const _processGroupItems = (

export const getDataSourceOptions = (
storeLoadAdapter,
column,
popupOptions,
headerFilterOptions,
filter,
) => {
const { column } = popupOptions;

if (!storeLoadAdapter) {
return undefined;
}
Expand Down Expand Up @@ -198,16 +202,20 @@ export const getDataSourceOptions = (
let items = data;

items = origPostProcess?.call(this, items) || items;
_updateSelectedState(items, column);
_updateSelectedState(items, {
...column,
filterType: popupOptions.filterType,
filterValues: popupOptions.filterValues,
});
return items;
};

return options.dataSource;
};

export const getFilterType = (
export const getHeaderFilterListType = (
column: Column,
): 'tree' | 'list' => {
): HeaderFilterListType => {
const groupInterval = filteringUtils.getGroupInterval(column);
return groupInterval && groupInterval.length > 1 ? 'tree' : 'list';
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import type { FilterType } from '@js/common/grids';
import type { DataSourceLike } from '@js/data/data_source';

import type { Column } from '../../columns_controller/types';

export type HeaderFilterSearchMode = 'contains' | 'startswith' | 'equals';
export type HeaderFilterType = 'include' | 'exclude';
export type HeaderFilterListType = 'tree' | 'list';

export interface PopupOptions {
type: HeaderFilterListType;
column: Column;
headerFilter: HeaderFilterColumnOptions;
dataSource?: DataSourceLike<unknown>;
isFilterBuilder?: boolean;
filterType?: FilterType;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
filterValues?: any[];
apply: () => void;
hidePopupCallback: () => void;
}

export type PopupState = {
element: Element;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
options: Record<string, any>;
options: PopupOptions;
} | null;

export interface HeaderFilterTextOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('HeaderFilter', () => {
{ popupState } as any,
);

popupState.value = { element: {} as any, options: expectedOptions };
popupState.value = { element: {} as any, options: expectedOptions as any };

expect(oldHeaderFilterMock.showHeaderFilterMenu)
.toHaveBeenCalledTimes(1);
Expand All @@ -130,7 +130,7 @@ describe('HeaderFilter', () => {
{ popupState } as any,
);

popupState.value = { element: {} as any, options: {} };
popupState.value = { element: {} as any, options: {} as any };
popupState.value = null;

expect(oldHeaderFilterMock.showHeaderFilterMenu)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ describe('HeaderFilter', () => {

const state = viewController.popupState.peek();

expect(typeof state?.options.dataSource.load).toBe('function');
expect(typeof state?.options.dataSource.postProcess).toBe('function');
expect(typeof (state?.options.dataSource as any).load).toBe('function');
expect(typeof (state?.options.dataSource as any).postProcess).toBe('function');
});

// NOTE: Unfortunately, we cannot test perfectly local group functions here
Expand Down Expand Up @@ -195,8 +195,8 @@ describe('HeaderFilter', () => {

const state = viewController.popupState.peek();

expect(state?.options.dataSource.group).toBeTruthy();
expect(checkFn(state?.options.dataSource.group)).toBeTruthy();
expect((state?.options.dataSource as any).group).toBeTruthy();
expect(checkFn((state?.options.dataSource as any).group)).toBeTruthy();
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { OptionsController } from '../../options_controller/options_controller';
import { FilterController } from '../filter_controller';
import type { AppliedFilters } from '../types';
import { getAppliedFilterExpressions } from '../utils';
import { getDataSourceOptions, getFilterType } from './legacy_header_filter';
import type { PopupState } from './types';
import { getDataSourceOptions, getHeaderFilterListType } from './legacy_header_filter';
import type { PopupOptions, PopupState } from './types';
import { getColumnIdentifier } from './utils';

export class HeaderFilterViewController {
Expand Down Expand Up @@ -45,70 +45,67 @@ export class HeaderFilterViewController {
const rootDataSource = this.dataController.getStoreLoadAdapter();
const rootHeaderFilterOptions = this.options.oneWay('headerFilter').peek();
const filterExpression = this.getFilterExpressionWithoutCurrentColumn(column);
const type = getHeaderFilterListType(column);
const { columnsController } = this;
const applyFilter = (filterValues, filterType): void => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like for moving legacy context arguments into function arguments 🙌

if (customApply) {
customApply(filterValues);
} else {
columnsController.updateColumns(
(columns) => {
const index = getColumnIndexByName(columns, column.name);
const newColumns = [...columns];

newColumns[index] = {
...newColumns[index],
headerFilter: {
...newColumns[index].headerFilter,
},
// NOTE: Copy array because of mutations in legacy code
filterValues: Array.isArray(filterValues)
? [...filterValues]
: filterValues,
filterType,
};
return newColumns;
},
);
}

onFilterCloseCallback?.();
};
const popupOptions: PopupOptions = {
type,
column: { ...column },
isFilterBuilder,
headerFilter: { ...column.headerFilter },
filterType: column.filterType,
// NOTE: Copy array because of mutations in legacy code
filterValues: Array.isArray(column.filterValues)
? [...column.filterValues]
: column.filterValues,
apply(): void {
applyFilter(this.filterValues, this.filterType);
},
hidePopupCallback: (): void => {
this.popupStateInternal.value = null;
onFilterCloseCallback?.();
},
};

const filterDataSourceOptions = getDataSourceOptions(
popupOptions.dataSource = getDataSourceOptions(
rootDataSource,
{
...column,
filterType: column.filterType,
filterValues: column.filterValues,
},
popupOptions,
// NOTE: Only text used from root options
{
texts: rootHeaderFilterOptions.texts,
},

filterExpression,
);

const type = getFilterType(column);
const { columnsController } = this;

this.popupStateInternal.value = {
element,
options: {
type,
isFilterBuilder,
headerFilter: { ...column.headerFilter },
dataSource: filterDataSourceOptions,
filterType: column.filterType,
// NOTE: Copy array because of mutations in legacy code
filterValues: Array.isArray(column.filterValues)

? [...column.filterValues]
: column.filterValues,
apply(): void {
if (customApply) {
customApply(this.filterValues);
} else {
columnsController.updateColumns(
(columns) => {
const index = getColumnIndexByName(columns, column.name);
const newColumns = [...columns];

newColumns[index] = {
...newColumns[index],
headerFilter: {
...newColumns[index].headerFilter,
},
// NOTE: Copy array because of mutations in legacy code
filterValues: Array.isArray(this.filterValues)
? [...this.filterValues]
: this.filterValues,
filterType: this.filterType,
};
return newColumns;
},
);
}

onFilterCloseCallback?.();
},
hidePopupCallback: (): void => {
this.popupStateInternal.value = null;
onFilterCloseCallback?.();
},
},
options: popupOptions,
};
}

Expand Down
Loading