Skip to content

Commit b676939

Browse files
committed
AI Assistant: add filter value to command default message
1 parent cf17123 commit b676939

3 files changed

Lines changed: 51 additions & 22 deletions

File tree

packages/devextreme/js/__internal/grids/grid_core/ai_assistant/commands/__tests__/filtering.test.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,15 @@ describe('filterValueCommand', () => {
204204
expect(result.status).toBe('success');
205205
});
206206

207-
it('returns failure when option throws', async () => {
207+
it('returns failure when applying the filter throws', async () => {
208208
const instance = await createGrid();
209-
jest.spyOn(instance, 'option').mockImplementationOnce(() => {
210-
throw new Error('Error');
211-
});
209+
const original = instance.option.bind(instance) as (...a: unknown[]) => unknown;
210+
jest.spyOn(instance, 'option').mockImplementation(((...args: unknown[]) => {
211+
if (args[0] === 'filterValue' && args.length > 1) {
212+
throw new Error('Error');
213+
}
214+
return original(...args);
215+
}) as never);
212216
const callbacks = createCallbacks();
213217

214218
const result = await filterValueCommand.execute(instance, callbacks)({
@@ -220,15 +224,15 @@ describe('filterValueCommand', () => {
220224
});
221225

222226
describe('default message', () => {
223-
it('uses `Apply a filter.` when expression is set', async () => {
227+
it('appends the human-readable filter text when expression is set', async () => {
224228
const instance = await createGrid();
225229
const callbacks = createCallbacks();
226230

227231
await filterValueCommand.execute(instance, callbacks)({
228232
expression: basicExpr('name', '=', 'Alpha'),
229233
});
230234

231-
expect(callbacks.success).toHaveBeenCalledWith('Apply a filter.');
235+
expect(callbacks.success).toHaveBeenCalledWith("Apply a filter: [Name] Equals 'Alpha'");
232236
});
233237

234238
it('uses `Clear filter.` when expression is null', async () => {
@@ -242,18 +246,22 @@ describe('filterValueCommand', () => {
242246
expect(callbacks.success).toHaveBeenCalledWith('Clear filter.');
243247
});
244248

245-
it('passes the same default message to failure when executability fails', async () => {
249+
it('passes the same readable default message to failure when applying the filter fails', async () => {
246250
const instance = await createGrid();
247-
jest.spyOn(instance, 'option').mockImplementationOnce(() => {
248-
throw new Error('Error');
249-
});
251+
const original = instance.option.bind(instance) as (...a: unknown[]) => unknown;
252+
jest.spyOn(instance, 'option').mockImplementation(((...args: unknown[]) => {
253+
if (args[0] === 'filterValue' && args.length > 1) {
254+
throw new Error('Error');
255+
}
256+
return original(...args);
257+
}) as never);
250258
const callbacks = createCallbacks();
251259

252260
await filterValueCommand.execute(instance, callbacks)({
253261
expression: basicExpr('name', '=', 'Alpha'),
254262
});
255263

256-
expect(callbacks.failure).toHaveBeenCalledWith('Apply a filter.');
264+
expect(callbacks.failure).toHaveBeenCalledWith("Apply a filter: [Name] Equals 'Alpha'");
257265
});
258266
});
259267
});

packages/devextreme/js/__internal/grids/grid_core/ai_assistant/commands/filtering.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { SearchOperation } from '@js/common/data.types';
2+
import { when } from '@js/core/utils/deferred';
23
import type { CommandResult } from '@ts/grids/grid_core/ai_assistant/types';
4+
import type { InternalGrid } from '@ts/grids/grid_core/m_types';
35
import { z } from 'zod';
46

57
import { defineGridCommand } from './defineGridCommand';
@@ -80,26 +82,44 @@ function convertFilterExprToArray(expr: FilterExprObj): FilterExprArray {
8082
}
8183
}
8284

85+
const getFilterValueDefaultMessage = async (
86+
component: InternalGrid,
87+
filterValue: unknown,
88+
): Promise<string> => {
89+
if (filterValue === undefined) {
90+
return 'Clear filter.';
91+
}
92+
93+
try {
94+
const filterText: string = await when(
95+
// Custom filter operations are omitted as not supported in command
96+
component.getView('filterPanelView').getFilterText(filterValue, []),
97+
);
98+
99+
return `Apply a filter: ${filterText}`;
100+
} catch {
101+
return 'Apply a filter.';
102+
}
103+
};
104+
83105
export const filterValueCommand = defineGridCommand({
84106
name: 'filterValue',
85107
description: 'Apply a filter expression to the grid. Replaces any existing filter; pass null for expression to clear. Expression forms: basic {"type":"basic","field":dataField,"operator":op,"value":val}, combined {"type":"combined","left":expr,"combiner":"and"|"or","right":expr}, negated {"type":"negated","expression":expr}. The "field" is the column dataField (not the caption). Supported operators: "=", "<>", "<", "<=", ">", ">=", "contains", "notcontains", "startswith", "endswith". To express "not and" / "not or", wrap the group in negation: {"type":"negated","expression":{"type":"combined",...}}.',
86108
schema: filterValueCommandSchema,
87-
execute: (component, { success, failure }) => (args): Promise<CommandResult> => {
88-
const defaultMessage = args.expression === null
89-
? 'Clear filter.'
90-
: 'Apply a filter.';
109+
execute: (component, { success, failure }) => async (args): Promise<CommandResult> => {
110+
const filterValue = args.expression === null
111+
? undefined
112+
: convertFilterExprToArray(args.expression);
91113

92-
try {
93-
const filterValue = args.expression === null
94-
? undefined
95-
: convertFilterExprToArray(args.expression);
114+
const defaultMessage = await getFilterValueDefaultMessage(component, filterValue);
96115

116+
try {
97117
// Handles remote operations via data controller listening for the `filtering` change
98118
component.option('filterValue', filterValue);
99119

100-
return Promise.resolve(success(defaultMessage));
120+
return success(defaultMessage);
101121
} catch {
102-
return Promise.resolve(failure(defaultMessage));
122+
return failure(defaultMessage);
103123
}
104124
},
105125
});

packages/devextreme/js/__internal/grids/grid_core/filter/m_filter_panel.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import eventsEngine from '@js/common/core/events/core/events_engine';
33
import messageLocalization from '@js/common/core/localization/message';
44
import type { dxElementWrapper } from '@js/core/renderer';
55
import $ from '@js/core/renderer';
6+
import type { DeferredObj } from '@js/core/utils/deferred';
67
import { Deferred, when } from '@js/core/utils/deferred';
78
import { isDefined } from '@js/core/utils/type';
89
import CheckBox from '@js/ui/check_box';
@@ -311,7 +312,7 @@ export class FilterPanelView extends modules.View {
311312
return result;
312313
}
313314

314-
private getFilterText(filterValue, customOperations) {
315+
public getFilterText(filterValue, customOperations): DeferredObj<string> {
315316
const options = {
316317
customOperations,
317318
columns: this._columnsController.getFilteringColumns(),

0 commit comments

Comments
 (0)