Skip to content

Commit f4fb1ec

Browse files
committed
copilot review fix
1 parent 45124c6 commit f4fb1ec

File tree

10 files changed

+130
-4
lines changed

10 files changed

+130
-4
lines changed

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,25 @@ describe('AIAssistantView', () => {
172172
});
173173
});
174174

175+
describe('hide', () => {
176+
it('should delegate to AIChat hide method', async () => {
177+
const { aiAssistantView } = createAIAssistantView();
178+
179+
await aiAssistantView.hide();
180+
181+
const aiChatInstance = (AIChat as jest.Mock)
182+
.mock.results[0].value as { hide: jest.Mock };
183+
184+
expect(aiChatInstance.hide).toHaveBeenCalledTimes(1);
185+
});
186+
187+
it('should return resolved false promise when aiChatInstance is not created', () => {
188+
const { aiAssistantView } = createAIAssistantView({ render: false });
189+
190+
return expect(aiAssistantView.hide()).resolves.toBe(false);
191+
});
192+
});
193+
175194
describe('isShown', () => {
176195
it('should delegate to AIChat isShown method', () => {
177196
const { aiAssistantView } = createAIAssistantView();

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { AIAssistantViewController } from '../ai_assistant_view_controller';
1111

1212
interface MockAIAssistantView {
1313
toggle: jest.Mock<() => Promise<boolean>>;
14+
hide: jest.Mock<() => Promise<boolean>>;
1415
isShown: jest.Mock<() => boolean>;
1516
onVisibilityChanged?: (visible: boolean) => void;
1617
}
@@ -23,6 +24,7 @@ interface MockHeaderPanel {
2324

2425
const createMockAIAssistantView = (): MockAIAssistantView => ({
2526
toggle: jest.fn<() => Promise<boolean>>().mockResolvedValue(true),
27+
hide: jest.fn<() => Promise<boolean>>().mockResolvedValue(true),
2628
isShown: jest.fn<() => boolean>().mockReturnValue(false),
2729
});
2830

@@ -116,5 +118,41 @@ describe('AIAssistantViewController', () => {
116118

117119
expect(args.handled).toBe(true);
118120
});
121+
122+
it('should hide popup when aiAssistant.enabled changes to false and popup is shown', () => {
123+
const options: Record<string, unknown> = { 'aiAssistant.enabled': true };
124+
const { controller, mockView } = createAIAssistantViewController(options);
125+
126+
mockView.isShown.mockReturnValue(true);
127+
options['aiAssistant.enabled'] = false;
128+
129+
controller.optionChanged({
130+
name: 'aiAssistant' as const,
131+
fullName: 'aiAssistant.enabled' as const,
132+
value: false,
133+
previousValue: true,
134+
handled: false,
135+
});
136+
137+
expect(mockView.hide).toHaveBeenCalledTimes(1);
138+
});
139+
140+
it('should not call hide when aiAssistant.enabled changes to false and popup is not shown', () => {
141+
const options: Record<string, unknown> = { 'aiAssistant.enabled': true };
142+
const { controller, mockView } = createAIAssistantViewController(options);
143+
144+
mockView.isShown.mockReturnValue(false);
145+
options['aiAssistant.enabled'] = false;
146+
147+
controller.optionChanged({
148+
name: 'aiAssistant' as const,
149+
fullName: 'aiAssistant.enabled' as const,
150+
value: false,
151+
previousValue: true,
152+
handled: false,
153+
});
154+
155+
expect(mockView.hide).not.toHaveBeenCalled();
156+
});
119157
});
120158
});

packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export class AIAssistantView extends View {
3333
return this.aiChatInstance?.isShown() ?? false;
3434
}
3535

36+
public hide(): Promise<boolean> {
37+
return this.aiChatInstance?.hide() ?? Promise.resolve(false);
38+
}
39+
3640
public toggle(): Promise<boolean> {
3741
return this.aiChatInstance?.toggle() ?? Promise.resolve(false);
3842
}

packages/devextreme/js/__internal/grids/grid_core/ai_assistant/ai_assistant_view_controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ export class AIAssistantViewController extends ViewController {
5959
this.headerPanel?.applyToolbarItem(AI_ASSISTANT_BUTTON_NAME, aiAssistantToolbarItem);
6060
} else {
6161
this.headerPanel?.removeToolbarItem(AI_ASSISTANT_BUTTON_NAME);
62+
63+
if (this.aiAssistantView?.isShown()) {
64+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
65+
this.aiAssistantView?.hide();
66+
}
6267
}
6368
}
6469

@@ -70,7 +75,7 @@ export class AIAssistantViewController extends ViewController {
7075

7176
if (this.headerPanel) {
7277
const aiAssistantClass = this.addWidgetPrefix(AI_ASSISTANT_BUTTON_CLASS);
73-
this.$aiAssistantButton.addClass(this.headerPanel._getToolbarButtonClass(aiAssistantClass));
78+
this.$aiAssistantButton.addClass(this.headerPanel.getToolbarButtonClass(aiAssistantClass));
7479
}
7580
};
7681
const hintText = this.option('aiAssistant.title'); // TODO clarify option name

packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type { AIChatOptions } from './types';
1717

1818
const mockPopupInstance = {
1919
toggle: jest.fn<() => Promise<boolean>>().mockResolvedValue(true),
20+
hide: jest.fn<() => Promise<boolean>>().mockResolvedValue(true),
2021
option: jest.fn<(name: string) => unknown>().mockReturnValue(false),
2122
};
2223

@@ -98,6 +99,17 @@ describe('AIChat', () => {
9899
});
99100
});
100101

102+
describe('hide', () => {
103+
it('should call popup hide method', async () => {
104+
const { aiChat } = createAIChat();
105+
106+
const result = await aiChat.hide();
107+
108+
expect(mockPopupInstance.hide).toHaveBeenCalledTimes(1);
109+
expect(result).toBe(true);
110+
});
111+
});
112+
101113
describe('isShown', () => {
102114
it('should return true when popup is visible', () => {
103115
const { aiChat } = createAIChat();
@@ -114,4 +126,47 @@ describe('AIChat', () => {
114126
expect(aiChat.isShown()).toBe(false);
115127
});
116128
});
129+
130+
describe('onVisibilityChanged', () => {
131+
const getPopupConfig = (): any => {
132+
const call = createComponentMock.mock.calls.find(
133+
([, Widget]) => Widget === Popup,
134+
);
135+
136+
expect(call).toBeDefined();
137+
138+
return (call as any)[2];
139+
};
140+
141+
it('should call onVisibilityChanged with true on showing', () => {
142+
const onVisibilityChanged = jest.fn();
143+
createAIChat({ onVisibilityChanged });
144+
145+
const popupConfig = getPopupConfig();
146+
popupConfig.onShowing();
147+
148+
expect(onVisibilityChanged).toHaveBeenCalledTimes(1);
149+
expect(onVisibilityChanged).toHaveBeenCalledWith(true);
150+
});
151+
152+
it('should call onVisibilityChanged with false on hidden', () => {
153+
const onVisibilityChanged = jest.fn();
154+
createAIChat({ onVisibilityChanged });
155+
156+
const popupConfig = getPopupConfig();
157+
popupConfig.onHidden();
158+
159+
expect(onVisibilityChanged).toHaveBeenCalledTimes(1);
160+
expect(onVisibilityChanged).toHaveBeenCalledWith(false);
161+
});
162+
163+
it('should not throw when onVisibilityChanged is not provided', () => {
164+
createAIChat();
165+
166+
const popupConfig = getPopupConfig();
167+
168+
expect(() => { popupConfig.onShowing(); }).not.toThrow();
169+
expect(() => { popupConfig.onHidden(); }).not.toThrow();
170+
});
171+
});
117172
});

packages/devextreme/js/__internal/grids/grid_core/ai_chat/ai_chat.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ export class AIChat {
5353
return this.popupInstance.toggle();
5454
}
5555

56+
public hide(): Promise<boolean> {
57+
return this.popupInstance.hide();
58+
}
59+
5660
public isShown(): boolean {
5761
return !!this.popupInstance.option('visible');
5862
}

packages/devextreme/js/__internal/grids/grid_core/ai_chat/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const DEFAULT_POPUP_OPTIONS = {
33
height: 'auto',
44
visible: false,
55
shading: false,
6+
showCloseButton: true,
67
};
78

89
export const CLASSES = {

packages/devextreme/js/__internal/grids/grid_core/column_chooser/m_column_chooser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ const headerPanel = (Base: ModuleType<HeaderPanel>) => class ColumnChooserHeader
539539
that.component.getView('columnChooserView').showColumnChooser();
540540
};
541541
const onInitialized = function (e) {
542-
$(e.element).addClass(that._getToolbarButtonClass(that.addWidgetPrefix(COLUMN_CHOOSER_BUTTON_CLASS)));
542+
$(e.element).addClass(that.getToolbarButtonClass(that.addWidgetPrefix(COLUMN_CHOOSER_BUTTON_CLASS)));
543543
};
544544
const hintText = that.option('columnChooser.title');
545545
const toolbarItem = {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ const headerPanel = (Base: ModuleType<HeaderPanel>) => class FilterRowHeaderPane
989989
const columns = that._columnsController.getColumns();
990990
const disabled = !columns.filter((column) => column.bufferedFilterValue !== undefined).length;
991991
const onInitialized = function (e) {
992-
$(e.element).addClass(that._getToolbarButtonClass(APPLY_BUTTON_CLASS));
992+
$(e.element).addClass(that.getToolbarButtonClass(APPLY_BUTTON_CLASS));
993993
};
994994
const onClickHandler = function () {
995995
that._applyFilterViewController.applyFilter();

packages/devextreme/js/__internal/grids/grid_core/header_panel/m_header_panel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export class HeaderPanel extends ColumnsView {
120120
return $('<div>').addClass(this.addWidgetPrefix(TOOLBAR_BUTTON_CLASS));
121121
}
122122

123-
public _getToolbarButtonClass(specificClass?: string): string {
123+
public getToolbarButtonClass(specificClass?: string): string {
124124
const secondClass = specificClass ? ` ${specificClass}` : '';
125125

126126
return this.addWidgetPrefix(TOOLBAR_BUTTON_CLASS) + secondClass;

0 commit comments

Comments
 (0)