@patternfly/chatbot 2.1.0-prerelease.19 → 2.1.0-prerelease.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +4 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.d.ts +1 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +73 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +4 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +2 -2
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.d.ts +1 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +69 -0
- package/dist/css/main.css +3 -0
- package/dist/css/main.css.map +1 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +4 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.d.ts +1 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +68 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +4 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +2 -2
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.d.ts +1 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +64 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +9 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +1 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +82 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +4 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +4 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +126 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +10 -1
@@ -16,7 +16,10 @@ const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect
|
|
16
16
|
const toggle = (toggleRef) => (react_1.default.createElement(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom" },
|
17
17
|
react_1.default.createElement(react_core_1.MenuToggle, { className: "pf-chatbot__history-actions", variant: "plain", "aria-label": label !== null && label !== void 0 ? label : 'Conversation options', ref: toggleRef, isExpanded: isOpen, onClick: () => setIsOpen(!isOpen), role: "menuitem" },
|
18
18
|
react_1.default.createElement(ellipsis_v_icon_1.default, null))));
|
19
|
-
return (react_1.default.createElement(react_core_1.Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect:
|
19
|
+
return (react_1.default.createElement(react_core_1.Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
|
20
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
21
|
+
setIsOpen((prev) => !prev);
|
22
|
+
}, onOpenChange: (isOpen) => setIsOpen(isOpen), popperProps: { position: 'right' }, shouldFocusToggleOnSelect: true, shouldFocusFirstItemOnOpen: true, toggle: toggle }, menuItems));
|
20
23
|
};
|
21
24
|
exports.ChatbotConversationHistoryDropdown = ChatbotConversationHistoryDropdown;
|
22
25
|
exports.default = exports.ChatbotConversationHistoryDropdown;
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,73 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
const react_1 = __importDefault(require("react"));
|
16
|
+
require("@testing-library/jest-dom");
|
17
|
+
const react_core_1 = require("@patternfly/react-core");
|
18
|
+
const react_2 = require("@testing-library/react");
|
19
|
+
const ChatbotConversationHistoryDropdown_1 = __importDefault(require("./ChatbotConversationHistoryDropdown"));
|
20
|
+
describe('ChatbotConversationHistoryDropdown', () => {
|
21
|
+
const onSelect = jest.fn();
|
22
|
+
const menuItems = (react_1.default.createElement(react_1.default.Fragment, null,
|
23
|
+
react_1.default.createElement(react_core_1.DropdownItem, null, "Rename"),
|
24
|
+
react_1.default.createElement(react_core_1.DropdownItem, null, "Delete")));
|
25
|
+
it('should render the dropdown', () => {
|
26
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, menuClassName: "custom-class" }));
|
27
|
+
expect(react_2.screen.queryByRole('menuitem', { name: /Conversation options/i })).toBeInTheDocument();
|
28
|
+
});
|
29
|
+
it('should display the dropdown menuItems', () => {
|
30
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems }));
|
31
|
+
const toggle = react_2.screen.queryByRole('menuitem', { name: /Conversation options/i });
|
32
|
+
expect(toggle).toBeInTheDocument();
|
33
|
+
react_2.fireEvent.click(toggle);
|
34
|
+
(0, react_2.waitFor)(() => {
|
35
|
+
expect(react_2.screen.getByText('Rename')).toBeInTheDocument();
|
36
|
+
expect(react_2.screen.getByText('Delete')).toBeInTheDocument();
|
37
|
+
});
|
38
|
+
});
|
39
|
+
it('should invoke onSelect callback when menuitem is clicked', () => {
|
40
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, onSelect: onSelect }));
|
41
|
+
const toggle = react_2.screen.queryByRole('menuitem', { name: /Conversation options/i });
|
42
|
+
react_2.fireEvent.click(toggle);
|
43
|
+
react_2.fireEvent.click(react_2.screen.getByText('Rename'));
|
44
|
+
expect(onSelect).toHaveBeenCalled();
|
45
|
+
});
|
46
|
+
it('should toggle the dropdown when menuitem is clicked', () => {
|
47
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, onSelect: onSelect }));
|
48
|
+
const toggle = react_2.screen.queryByRole('menuitem', { name: /Conversation options/i });
|
49
|
+
react_2.fireEvent.click(toggle);
|
50
|
+
react_2.fireEvent.click(react_2.screen.getByText('Delete'));
|
51
|
+
expect(onSelect).toHaveBeenCalled();
|
52
|
+
expect(react_2.screen.queryByText('Delete')).not.toBeInTheDocument();
|
53
|
+
});
|
54
|
+
it('should close the dropdown when user clicks outside', () => {
|
55
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, onSelect: onSelect }));
|
56
|
+
const toggle = react_2.screen.queryByRole('menuitem', { name: /Conversation options/i });
|
57
|
+
react_2.fireEvent.click(toggle);
|
58
|
+
expect(react_2.screen.queryByText('Delete')).toBeInTheDocument();
|
59
|
+
react_2.fireEvent.click(toggle.parentElement);
|
60
|
+
expect(react_2.screen.queryByText('Delete')).not.toBeInTheDocument();
|
61
|
+
});
|
62
|
+
it('should show the tooltip when the user hovers over the toggle button', () => __awaiter(void 0, void 0, void 0, function* () {
|
63
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryDropdown_1.default, { menuItems: menuItems, label: "Actions dropdown" }));
|
64
|
+
const toggle = react_2.screen.queryByRole('menuitem', { name: /Actions dropdown/i });
|
65
|
+
(0, react_2.fireEvent)(toggle, new MouseEvent('mouseenter', {
|
66
|
+
bubbles: false,
|
67
|
+
cancelable: false
|
68
|
+
}));
|
69
|
+
yield (0, react_2.waitFor)(() => {
|
70
|
+
expect(react_2.screen.queryByText('Actions dropdown')).toBeInTheDocument();
|
71
|
+
});
|
72
|
+
}));
|
73
|
+
});
|
@@ -47,6 +47,10 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
47
47
|
handleTextInputChange?: (value: string) => void;
|
48
48
|
/** Display mode of chatbot */
|
49
49
|
displayMode: ChatbotDisplayMode;
|
50
|
+
/** Reverses the order of the drawer action buttons */
|
51
|
+
reverseButtonOrder?: boolean;
|
52
|
+
/** Custom test id for the drawer actions */
|
53
|
+
drawerActionsTestId?: string;
|
50
54
|
}
|
51
55
|
export declare const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConversationHistoryNavProps>;
|
52
56
|
export default ChatbotConversationHistoryNav;
|
@@ -25,7 +25,7 @@ const react_icons_1 = require("@patternfly/react-icons");
|
|
25
25
|
const Chatbot_1 = require("../Chatbot/Chatbot");
|
26
26
|
const ChatbotConversationHistoryDropdown_1 = __importDefault(require("./ChatbotConversationHistoryDropdown"));
|
27
27
|
const ChatbotConversationHistoryNav = (_a) => {
|
28
|
-
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, newChatButtonText = 'New chat', drawerContent, onNewChat, searchInputPlaceholder = 'Search...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "newChatButtonText", "drawerContent", "onNewChat", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode"]);
|
28
|
+
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, newChatButtonText = 'New chat', drawerContent, onNewChat, searchInputPlaceholder = 'Search...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "newChatButtonText", "drawerContent", "onNewChat", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId"]);
|
29
29
|
const drawerRef = react_1.default.useRef(null);
|
30
30
|
const onExpand = () => {
|
31
31
|
drawerRef.current && drawerRef.current.focus();
|
@@ -56,7 +56,7 @@ const ChatbotConversationHistoryNav = (_a) => {
|
|
56
56
|
react_1.default.createElement(react_core_1.MenuContent, null, buildMenu())));
|
57
57
|
const panelContent = (react_1.default.createElement(react_core_1.DrawerPanelContent, { focusTrap: { enabled: true }, minSize: "384px", maxSize: "384px" },
|
58
58
|
react_1.default.createElement(react_core_1.DrawerHead, null,
|
59
|
-
react_1.default.createElement(react_core_1.DrawerActions,
|
59
|
+
react_1.default.createElement(react_core_1.DrawerActions, { "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' },
|
60
60
|
react_1.default.createElement(react_core_1.DrawerCloseButton, { onClick: onDrawerToggle }),
|
61
61
|
onNewChat && react_1.default.createElement(react_core_1.Button, { onClick: onNewChat }, newChatButtonText))),
|
62
62
|
handleTextInputChange && (react_1.default.createElement("div", { className: "pf-chatbot__input" },
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,69 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
const react_1 = __importDefault(require("react"));
|
16
|
+
require("@testing-library/jest-dom");
|
17
|
+
const react_2 = require("@testing-library/react");
|
18
|
+
const Chatbot_1 = require("../Chatbot/Chatbot");
|
19
|
+
const ChatbotConversationHistoryNav_1 = __importDefault(require("./ChatbotConversationHistoryNav"));
|
20
|
+
describe('ChatbotConversationHistoryNav', () => {
|
21
|
+
const onDrawerToggle = jest.fn();
|
22
|
+
const initialConversations = [
|
23
|
+
{
|
24
|
+
id: '1',
|
25
|
+
text: 'Lightspeed documentation'
|
26
|
+
}
|
27
|
+
];
|
28
|
+
it('should open the conversation history navigation drawer', () => {
|
29
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: initialConversations }));
|
30
|
+
expect(react_2.screen.queryByText('Lightspeed documentation')).toBeInTheDocument();
|
31
|
+
});
|
32
|
+
it('should display the conversations for grouped conversations', () => {
|
33
|
+
const groupedConversations = {
|
34
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
35
|
+
};
|
36
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: groupedConversations }));
|
37
|
+
expect(react_2.screen.queryByText('Chatbot extension')).toBeInTheDocument();
|
38
|
+
});
|
39
|
+
it('should apply the reversed class when reverseButtonOrder is true', () => {
|
40
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: true, conversations: initialConversations }));
|
41
|
+
expect(react_2.screen.getByTestId('chatbot-nav-drawer-actions')).toHaveClass('pf-v6-c-drawer__actions--reversed');
|
42
|
+
});
|
43
|
+
it('should not apply the reversed class when reverseButtonOrder is false', () => {
|
44
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, conversations: initialConversations }));
|
45
|
+
expect(react_2.screen.getByTestId('chatbot-nav-drawer-actions')).not.toHaveClass('pf-v6-c-drawer__actions--reversed');
|
46
|
+
});
|
47
|
+
it('should invoke handleTextInputChange callback when user searches for conversations', () => {
|
48
|
+
const handleSearch = jest.fn();
|
49
|
+
const groupedConversations = {
|
50
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
51
|
+
};
|
52
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, conversations: groupedConversations, handleTextInputChange: handleSearch }));
|
53
|
+
const searchInput = react_2.screen.getByPlaceholderText(/Search/i);
|
54
|
+
react_2.fireEvent.change(searchInput, { target: { value: 'Chatbot' } });
|
55
|
+
expect(handleSearch).toHaveBeenCalledWith('Chatbot');
|
56
|
+
});
|
57
|
+
it('should close the drawer when escape key is pressed', () => __awaiter(void 0, void 0, void 0, function* () {
|
58
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, handleTextInputChange: jest.fn(), conversations: initialConversations }));
|
59
|
+
react_2.fireEvent.keyDown(react_2.screen.getByPlaceholderText(/Search/i), {
|
60
|
+
key: 'Escape',
|
61
|
+
code: 'Escape',
|
62
|
+
keyCode: 27,
|
63
|
+
charCode: 27
|
64
|
+
});
|
65
|
+
(0, react_2.waitFor)(() => {
|
66
|
+
expect(react_2.screen.queryByText('Lightspeed documentation')).not.toBeInTheDocument();
|
67
|
+
});
|
68
|
+
}));
|
69
|
+
});
|
package/dist/css/main.css
CHANGED
@@ -223,6 +223,9 @@ html.pf-chatbot-allow--docked {
|
|
223
223
|
width: 100%;
|
224
224
|
height: 100%;
|
225
225
|
}
|
226
|
+
.pf-chatbot__history.pf-v6-c-drawer .pf-v6-c-drawer__actions--reversed {
|
227
|
+
flex-direction: row-reverse;
|
228
|
+
}
|
226
229
|
.pf-chatbot__history.pf-v6-c-drawer .pf-v6-c-drawer__close .pf-v6-c-button {
|
227
230
|
width: var(--pf-t--global--spacer--2xl);
|
228
231
|
height: var(--pf-t--global--spacer--2xl);
|
package/dist/css/main.css.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;ACvFF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;IACA;;;ACfJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAQF;EACE;;;AAQF;EACE;;AACA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AASF;AAAA;AAAA;EACE;;;
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;ACvFF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;IACA;;;ACfJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAQF;EACE;;;AAQF;EACE;;AACA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AASF;AAAA;AAAA;EACE;;;AClKN;EACE;;AAEA;EACE;EACA;;;ACHJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;;EACA;AAAA;IACE;;EAGJ;AAAA;IACE;IACA;;;AAUF;EACE;;AAGJ;EACE;;;AChDJ;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;;AAQN;EAGI;AAAA;IACE;;EAEF;AAAA;IACE;;;AASJ;EACE;;AAEF;EACE;;;AAOJ;AAAA;EAEE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAOJ;EACE;;;AAOJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;;;AC1IF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;AAAA;EAEE;;AAEF;EACE;EACA;;AAEF;EACE;;;AAOJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAGJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAOJ;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAQE;EACE;;;AAQN;EACE;;;ACvFA;EAA0B;;AAMxB;EAAM;;AACN;EAAuB;;AACvB;EACE;;AAIF;EACE;EACA;;AAEF;EACE;;;ACnBN;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;;AAIF;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;;AC3BF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;;AAOJ;EAIM;AAAA;IACE;IACA;;;AC1CN;EACE;EACA;EACA;EACA;;AAEF;EACE;AACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;;;AASA;EACE;EACA;;;ACxEN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EAEA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;EAEE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;;;AAKF;EACE;;AAGF;EACE;;;AAIJ;AAAA;EAEE;EACA;;AAEA;AAAA;EACE;;;AAKF;EACE;;;AAMF;AAAA;EACE;;;AC/DJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;EACA;;;AC/BF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAKJ;EACE;;AAEF;EACE;;AAMJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAIA;EACE;;AAEA;EAHF;IAII;;;AAGF;EAPF;IAQI;;;;AAQR;EACE;EACA;EACA;;;ACnHF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AC9CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1EE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;;;AD5CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1EE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;;;AC3CN;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAKF;AAAA;EAEE;EACA;EACA;;;AHnBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AI9CN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKA;EACE;;;ACbN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;AAKJ;EACE;EACA;;AAGA;EACE;;AAKA;EACE;;;AAMR;EACE;IACE;;EAEF;IACE;;;AC1CJ;EACE;EACA;EACA;EACA;;AAEA;EAEE;;AAEA;EACE;;;AAKN;EACE;IACE;IACA;;EAEF;IACE;IACA;;;ACvBJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EAEE;;;ACTJ;EACE;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACvEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACzCJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAGI;AAAA;IACE;IACA;;;AD5BN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;AE3CJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;;ACrBR;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;EACE;;AAGJ;EACE;EACA;;AAKA;AAAA;EACE;;AAGJ;EACE;;;ACrER;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;ACJF;EAKE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASA;EACA;EAEA;EAEA;EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAMA;EAKA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;;;AAMF;EACE;EACA;EAEA;EAEA;EACA;;;AAGF;EACE;EACA","file":"main.css"}
|
@@ -10,6 +10,9 @@ export const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, o
|
|
10
10
|
const toggle = (toggleRef) => (React.createElement(Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom" },
|
11
11
|
React.createElement(MenuToggle, { className: "pf-chatbot__history-actions", variant: "plain", "aria-label": label !== null && label !== void 0 ? label : 'Conversation options', ref: toggleRef, isExpanded: isOpen, onClick: () => setIsOpen(!isOpen), role: "menuitem" },
|
12
12
|
React.createElement(EllipsisIcon, null))));
|
13
|
-
return (React.createElement(Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect:
|
13
|
+
return (React.createElement(Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
|
14
|
+
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
15
|
+
setIsOpen((prev) => !prev);
|
16
|
+
}, onOpenChange: (isOpen) => setIsOpen(isOpen), popperProps: { position: 'right' }, shouldFocusToggleOnSelect: true, shouldFocusFirstItemOnOpen: true, toggle: toggle }, menuItems));
|
14
17
|
};
|
15
18
|
export default ChatbotConversationHistoryDropdown;
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,68 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
import React from 'react';
|
11
|
+
import '@testing-library/jest-dom';
|
12
|
+
import { DropdownItem } from '@patternfly/react-core';
|
13
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
14
|
+
import ChatbotConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
|
15
|
+
describe('ChatbotConversationHistoryDropdown', () => {
|
16
|
+
const onSelect = jest.fn();
|
17
|
+
const menuItems = (React.createElement(React.Fragment, null,
|
18
|
+
React.createElement(DropdownItem, null, "Rename"),
|
19
|
+
React.createElement(DropdownItem, null, "Delete")));
|
20
|
+
it('should render the dropdown', () => {
|
21
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems, menuClassName: "custom-class" }));
|
22
|
+
expect(screen.queryByRole('menuitem', { name: /Conversation options/i })).toBeInTheDocument();
|
23
|
+
});
|
24
|
+
it('should display the dropdown menuItems', () => {
|
25
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems }));
|
26
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i });
|
27
|
+
expect(toggle).toBeInTheDocument();
|
28
|
+
fireEvent.click(toggle);
|
29
|
+
waitFor(() => {
|
30
|
+
expect(screen.getByText('Rename')).toBeInTheDocument();
|
31
|
+
expect(screen.getByText('Delete')).toBeInTheDocument();
|
32
|
+
});
|
33
|
+
});
|
34
|
+
it('should invoke onSelect callback when menuitem is clicked', () => {
|
35
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems, onSelect: onSelect }));
|
36
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i });
|
37
|
+
fireEvent.click(toggle);
|
38
|
+
fireEvent.click(screen.getByText('Rename'));
|
39
|
+
expect(onSelect).toHaveBeenCalled();
|
40
|
+
});
|
41
|
+
it('should toggle the dropdown when menuitem is clicked', () => {
|
42
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems, onSelect: onSelect }));
|
43
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i });
|
44
|
+
fireEvent.click(toggle);
|
45
|
+
fireEvent.click(screen.getByText('Delete'));
|
46
|
+
expect(onSelect).toHaveBeenCalled();
|
47
|
+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
|
48
|
+
});
|
49
|
+
it('should close the dropdown when user clicks outside', () => {
|
50
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems, onSelect: onSelect }));
|
51
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i });
|
52
|
+
fireEvent.click(toggle);
|
53
|
+
expect(screen.queryByText('Delete')).toBeInTheDocument();
|
54
|
+
fireEvent.click(toggle.parentElement);
|
55
|
+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
|
56
|
+
});
|
57
|
+
it('should show the tooltip when the user hovers over the toggle button', () => __awaiter(void 0, void 0, void 0, function* () {
|
58
|
+
render(React.createElement(ChatbotConversationHistoryDropdown, { menuItems: menuItems, label: "Actions dropdown" }));
|
59
|
+
const toggle = screen.queryByRole('menuitem', { name: /Actions dropdown/i });
|
60
|
+
fireEvent(toggle, new MouseEvent('mouseenter', {
|
61
|
+
bubbles: false,
|
62
|
+
cancelable: false
|
63
|
+
}));
|
64
|
+
yield waitFor(() => {
|
65
|
+
expect(screen.queryByText('Actions dropdown')).toBeInTheDocument();
|
66
|
+
});
|
67
|
+
}));
|
68
|
+
});
|
@@ -47,6 +47,10 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
47
47
|
handleTextInputChange?: (value: string) => void;
|
48
48
|
/** Display mode of chatbot */
|
49
49
|
displayMode: ChatbotDisplayMode;
|
50
|
+
/** Reverses the order of the drawer action buttons */
|
51
|
+
reverseButtonOrder?: boolean;
|
52
|
+
/** Custom test id for the drawer actions */
|
53
|
+
drawerActionsTestId?: string;
|
50
54
|
}
|
51
55
|
export declare const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConversationHistoryNavProps>;
|
52
56
|
export default ChatbotConversationHistoryNav;
|
@@ -19,7 +19,7 @@ import { OutlinedCommentAltIcon } from '@patternfly/react-icons';
|
|
19
19
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
20
20
|
import ConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
|
21
21
|
export const ChatbotConversationHistoryNav = (_a) => {
|
22
|
-
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, newChatButtonText = 'New chat', drawerContent, onNewChat, searchInputPlaceholder = 'Search...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "newChatButtonText", "drawerContent", "onNewChat", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode"]);
|
22
|
+
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, newChatButtonText = 'New chat', drawerContent, onNewChat, searchInputPlaceholder = 'Search...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "newChatButtonText", "drawerContent", "onNewChat", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId"]);
|
23
23
|
const drawerRef = React.useRef(null);
|
24
24
|
const onExpand = () => {
|
25
25
|
drawerRef.current && drawerRef.current.focus();
|
@@ -50,7 +50,7 @@ export const ChatbotConversationHistoryNav = (_a) => {
|
|
50
50
|
React.createElement(MenuContent, null, buildMenu())));
|
51
51
|
const panelContent = (React.createElement(DrawerPanelContent, { focusTrap: { enabled: true }, minSize: "384px", maxSize: "384px" },
|
52
52
|
React.createElement(DrawerHead, null,
|
53
|
-
React.createElement(DrawerActions,
|
53
|
+
React.createElement(DrawerActions, { "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' },
|
54
54
|
React.createElement(DrawerCloseButton, { onClick: onDrawerToggle }),
|
55
55
|
onNewChat && React.createElement(Button, { onClick: onNewChat }, newChatButtonText))),
|
56
56
|
handleTextInputChange && (React.createElement("div", { className: "pf-chatbot__input" },
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,64 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
import React from 'react';
|
11
|
+
import '@testing-library/jest-dom';
|
12
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
13
|
+
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
14
|
+
import ChatbotConversationHistoryNav from './ChatbotConversationHistoryNav';
|
15
|
+
describe('ChatbotConversationHistoryNav', () => {
|
16
|
+
const onDrawerToggle = jest.fn();
|
17
|
+
const initialConversations = [
|
18
|
+
{
|
19
|
+
id: '1',
|
20
|
+
text: 'Lightspeed documentation'
|
21
|
+
}
|
22
|
+
];
|
23
|
+
it('should open the conversation history navigation drawer', () => {
|
24
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: initialConversations }));
|
25
|
+
expect(screen.queryByText('Lightspeed documentation')).toBeInTheDocument();
|
26
|
+
});
|
27
|
+
it('should display the conversations for grouped conversations', () => {
|
28
|
+
const groupedConversations = {
|
29
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
30
|
+
};
|
31
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: groupedConversations }));
|
32
|
+
expect(screen.queryByText('Chatbot extension')).toBeInTheDocument();
|
33
|
+
});
|
34
|
+
it('should apply the reversed class when reverseButtonOrder is true', () => {
|
35
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: true, conversations: initialConversations }));
|
36
|
+
expect(screen.getByTestId('chatbot-nav-drawer-actions')).toHaveClass('pf-v6-c-drawer__actions--reversed');
|
37
|
+
});
|
38
|
+
it('should not apply the reversed class when reverseButtonOrder is false', () => {
|
39
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, conversations: initialConversations }));
|
40
|
+
expect(screen.getByTestId('chatbot-nav-drawer-actions')).not.toHaveClass('pf-v6-c-drawer__actions--reversed');
|
41
|
+
});
|
42
|
+
it('should invoke handleTextInputChange callback when user searches for conversations', () => {
|
43
|
+
const handleSearch = jest.fn();
|
44
|
+
const groupedConversations = {
|
45
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
46
|
+
};
|
47
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, conversations: groupedConversations, handleTextInputChange: handleSearch }));
|
48
|
+
const searchInput = screen.getByPlaceholderText(/Search/i);
|
49
|
+
fireEvent.change(searchInput, { target: { value: 'Chatbot' } });
|
50
|
+
expect(handleSearch).toHaveBeenCalledWith('Chatbot');
|
51
|
+
});
|
52
|
+
it('should close the drawer when escape key is pressed', () => __awaiter(void 0, void 0, void 0, function* () {
|
53
|
+
render(React.createElement(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), reverseButtonOrder: false, handleTextInputChange: jest.fn(), conversations: initialConversations }));
|
54
|
+
fireEvent.keyDown(screen.getByPlaceholderText(/Search/i), {
|
55
|
+
key: 'Escape',
|
56
|
+
code: 'Escape',
|
57
|
+
keyCode: 27,
|
58
|
+
charCode: 27
|
59
|
+
});
|
60
|
+
waitFor(() => {
|
61
|
+
expect(screen.queryByText('Lightspeed documentation')).not.toBeInTheDocument();
|
62
|
+
});
|
63
|
+
}));
|
64
|
+
});
|
@@ -1 +1 @@
|
|
1
|
-
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts"],"version":"5.6.3"}
|
1
|
+
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts"],"version":"5.6.3"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@patternfly/chatbot",
|
3
|
-
"version": "2.1.0-prerelease.
|
3
|
+
"version": "2.1.0-prerelease.21",
|
4
4
|
"description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
|
5
5
|
"main": "dist/cjs/index.js",
|
6
6
|
"module": "dist/esm/index.js",
|
@@ -33,6 +33,7 @@ const initialConversations: { [key: string]: Conversation[] } = {
|
|
33
33
|
|
34
34
|
export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
35
35
|
const [isOpen, setIsOpen] = React.useState(true);
|
36
|
+
const [isButtonOrderReversed, setIsbuttonOrderReversed] = React.useState(false);
|
36
37
|
const [conversations, setConversations] = React.useState<Conversation[] | { [key: string]: Conversation[] }>(
|
37
38
|
initialConversations
|
38
39
|
);
|
@@ -66,6 +67,13 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
66
67
|
id="drawer-visible"
|
67
68
|
name="drawer-visible"
|
68
69
|
/>
|
70
|
+
<Checkbox
|
71
|
+
label="Reverse action buttons"
|
72
|
+
isChecked={isButtonOrderReversed}
|
73
|
+
onChange={() => setIsbuttonOrderReversed(!isButtonOrderReversed)}
|
74
|
+
id="drawer-actions-visible"
|
75
|
+
name="drawer-actions-visible"
|
76
|
+
></Checkbox>
|
69
77
|
<ChatbotConversationHistoryNav
|
70
78
|
displayMode={displayMode}
|
71
79
|
onDrawerToggle={() => setIsOpen(!isOpen)}
|
@@ -77,6 +85,7 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
77
85
|
onNewChat={() => {
|
78
86
|
setIsOpen(!isOpen);
|
79
87
|
}}
|
88
|
+
reverseButtonOrder={isButtonOrderReversed}
|
80
89
|
handleTextInputChange={(value: string) => {
|
81
90
|
if (value === '') {
|
82
91
|
setConversations(initialConversations);
|
@@ -321,7 +321,7 @@ In the conversation history drawer, users can search previous chatbot conversati
|
|
321
321
|
|
322
322
|
They can also start new conversations via a "New chat" button. To customize the button label, use `newChatButtonText`.
|
323
323
|
|
324
|
-
Both the search input field and "New chat" buttons are optional.
|
324
|
+
Both the search input field and "New chat" buttons are optional. The `reverseButtonOrder` prop allows you to invert the positions of the Close and "New chat" buttons within the drawer when set to `true`.
|
325
325
|
|
326
326
|
```js file="./ChatbotHeaderDrawer.tsx"
|
327
327
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import '@testing-library/jest-dom';
|
3
|
+
import { DropdownItem } from '@patternfly/react-core';
|
4
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
5
|
+
import ChatbotConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
|
6
|
+
|
7
|
+
describe('ChatbotConversationHistoryDropdown', () => {
|
8
|
+
const onSelect = jest.fn();
|
9
|
+
const menuItems = (
|
10
|
+
<>
|
11
|
+
<DropdownItem>Rename</DropdownItem>
|
12
|
+
<DropdownItem>Delete</DropdownItem>
|
13
|
+
</>
|
14
|
+
);
|
15
|
+
|
16
|
+
it('should render the dropdown', () => {
|
17
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} menuClassName="custom-class" />);
|
18
|
+
expect(screen.queryByRole('menuitem', { name: /Conversation options/i })).toBeInTheDocument();
|
19
|
+
});
|
20
|
+
|
21
|
+
it('should display the dropdown menuItems', () => {
|
22
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} />);
|
23
|
+
|
24
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i })!;
|
25
|
+
|
26
|
+
expect(toggle).toBeInTheDocument();
|
27
|
+
fireEvent.click(toggle);
|
28
|
+
|
29
|
+
waitFor(() => {
|
30
|
+
expect(screen.getByText('Rename')).toBeInTheDocument();
|
31
|
+
expect(screen.getByText('Delete')).toBeInTheDocument();
|
32
|
+
});
|
33
|
+
});
|
34
|
+
|
35
|
+
it('should invoke onSelect callback when menuitem is clicked', () => {
|
36
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} onSelect={onSelect} />);
|
37
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i })!;
|
38
|
+
fireEvent.click(toggle);
|
39
|
+
fireEvent.click(screen.getByText('Rename'));
|
40
|
+
|
41
|
+
expect(onSelect).toHaveBeenCalled();
|
42
|
+
});
|
43
|
+
|
44
|
+
it('should toggle the dropdown when menuitem is clicked', () => {
|
45
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} onSelect={onSelect} />);
|
46
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i })!;
|
47
|
+
fireEvent.click(toggle);
|
48
|
+
fireEvent.click(screen.getByText('Delete'));
|
49
|
+
|
50
|
+
expect(onSelect).toHaveBeenCalled();
|
51
|
+
|
52
|
+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should close the dropdown when user clicks outside', () => {
|
56
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} onSelect={onSelect} />);
|
57
|
+
const toggle = screen.queryByRole('menuitem', { name: /Conversation options/i })!;
|
58
|
+
fireEvent.click(toggle);
|
59
|
+
|
60
|
+
expect(screen.queryByText('Delete')).toBeInTheDocument();
|
61
|
+
fireEvent.click(toggle.parentElement!);
|
62
|
+
|
63
|
+
expect(screen.queryByText('Delete')).not.toBeInTheDocument();
|
64
|
+
});
|
65
|
+
|
66
|
+
it('should show the tooltip when the user hovers over the toggle button', async () => {
|
67
|
+
render(<ChatbotConversationHistoryDropdown menuItems={menuItems} label="Actions dropdown" />);
|
68
|
+
const toggle = screen.queryByRole('menuitem', { name: /Actions dropdown/i })!;
|
69
|
+
|
70
|
+
fireEvent(
|
71
|
+
toggle,
|
72
|
+
new MouseEvent('mouseenter', {
|
73
|
+
bubbles: false,
|
74
|
+
cancelable: false
|
75
|
+
})
|
76
|
+
);
|
77
|
+
|
78
|
+
await waitFor(() => {
|
79
|
+
expect(screen.queryByText('Actions dropdown')).toBeInTheDocument();
|
80
|
+
});
|
81
|
+
});
|
82
|
+
});
|
@@ -47,7 +47,10 @@ export const ChatbotConversationHistoryDropdown: React.FunctionComponent<Chatbot
|
|
47
47
|
<Dropdown
|
48
48
|
className={`pf-chatbot__selections ${menuClassName ?? ''}`}
|
49
49
|
isOpen={isOpen}
|
50
|
-
onSelect={
|
50
|
+
onSelect={(props) => {
|
51
|
+
onSelect?.(props);
|
52
|
+
setIsOpen((prev) => !prev);
|
53
|
+
}}
|
51
54
|
onOpenChange={(isOpen) => setIsOpen(isOpen)}
|
52
55
|
popperProps={{ position: 'right' }}
|
53
56
|
shouldFocusToggleOnSelect
|
@@ -0,0 +1,126 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import '@testing-library/jest-dom';
|
3
|
+
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
4
|
+
|
5
|
+
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
6
|
+
import ChatbotConversationHistoryNav, { Conversation } from './ChatbotConversationHistoryNav';
|
7
|
+
|
8
|
+
describe('ChatbotConversationHistoryNav', () => {
|
9
|
+
const onDrawerToggle = jest.fn();
|
10
|
+
|
11
|
+
const initialConversations: Conversation[] = [
|
12
|
+
{
|
13
|
+
id: '1',
|
14
|
+
text: 'Lightspeed documentation'
|
15
|
+
}
|
16
|
+
];
|
17
|
+
|
18
|
+
it('should open the conversation history navigation drawer', () => {
|
19
|
+
render(
|
20
|
+
<ChatbotConversationHistoryNav
|
21
|
+
onDrawerToggle={onDrawerToggle}
|
22
|
+
isDrawerOpen={true}
|
23
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
24
|
+
setIsDrawerOpen={jest.fn()}
|
25
|
+
conversations={initialConversations}
|
26
|
+
/>
|
27
|
+
);
|
28
|
+
expect(screen.queryByText('Lightspeed documentation')).toBeInTheDocument();
|
29
|
+
});
|
30
|
+
|
31
|
+
it('should display the conversations for grouped conversations', () => {
|
32
|
+
const groupedConversations: { [key: string]: Conversation[] } = {
|
33
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
34
|
+
};
|
35
|
+
|
36
|
+
render(
|
37
|
+
<ChatbotConversationHistoryNav
|
38
|
+
onDrawerToggle={onDrawerToggle}
|
39
|
+
isDrawerOpen={true}
|
40
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
41
|
+
setIsDrawerOpen={jest.fn()}
|
42
|
+
conversations={groupedConversations}
|
43
|
+
/>
|
44
|
+
);
|
45
|
+
expect(screen.queryByText('Chatbot extension')).toBeInTheDocument();
|
46
|
+
});
|
47
|
+
|
48
|
+
it('should apply the reversed class when reverseButtonOrder is true', () => {
|
49
|
+
render(
|
50
|
+
<ChatbotConversationHistoryNav
|
51
|
+
onDrawerToggle={onDrawerToggle}
|
52
|
+
isDrawerOpen={true}
|
53
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
54
|
+
setIsDrawerOpen={jest.fn()}
|
55
|
+
reverseButtonOrder
|
56
|
+
conversations={initialConversations}
|
57
|
+
/>
|
58
|
+
);
|
59
|
+
|
60
|
+
expect(screen.getByTestId('chatbot-nav-drawer-actions')).toHaveClass('pf-v6-c-drawer__actions--reversed');
|
61
|
+
});
|
62
|
+
|
63
|
+
it('should not apply the reversed class when reverseButtonOrder is false', () => {
|
64
|
+
render(
|
65
|
+
<ChatbotConversationHistoryNav
|
66
|
+
onDrawerToggle={onDrawerToggle}
|
67
|
+
isDrawerOpen={true}
|
68
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
69
|
+
setIsDrawerOpen={jest.fn()}
|
70
|
+
reverseButtonOrder={false}
|
71
|
+
conversations={initialConversations}
|
72
|
+
/>
|
73
|
+
);
|
74
|
+
expect(screen.getByTestId('chatbot-nav-drawer-actions')).not.toHaveClass('pf-v6-c-drawer__actions--reversed');
|
75
|
+
});
|
76
|
+
|
77
|
+
it('should invoke handleTextInputChange callback when user searches for conversations', () => {
|
78
|
+
const handleSearch = jest.fn();
|
79
|
+
const groupedConversations: { [key: string]: Conversation[] } = {
|
80
|
+
Today: [...initialConversations, { id: '2', text: 'Chatbot extension' }]
|
81
|
+
};
|
82
|
+
|
83
|
+
render(
|
84
|
+
<ChatbotConversationHistoryNav
|
85
|
+
onDrawerToggle={onDrawerToggle}
|
86
|
+
isDrawerOpen={true}
|
87
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
88
|
+
setIsDrawerOpen={jest.fn()}
|
89
|
+
reverseButtonOrder={false}
|
90
|
+
conversations={groupedConversations}
|
91
|
+
handleTextInputChange={handleSearch}
|
92
|
+
/>
|
93
|
+
);
|
94
|
+
|
95
|
+
const searchInput = screen.getByPlaceholderText(/Search/i);
|
96
|
+
|
97
|
+
fireEvent.change(searchInput, { target: { value: 'Chatbot' } });
|
98
|
+
|
99
|
+
expect(handleSearch).toHaveBeenCalledWith('Chatbot');
|
100
|
+
});
|
101
|
+
|
102
|
+
it('should close the drawer when escape key is pressed', async () => {
|
103
|
+
render(
|
104
|
+
<ChatbotConversationHistoryNav
|
105
|
+
onDrawerToggle={onDrawerToggle}
|
106
|
+
isDrawerOpen={true}
|
107
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
108
|
+
setIsDrawerOpen={jest.fn()}
|
109
|
+
reverseButtonOrder={false}
|
110
|
+
handleTextInputChange={jest.fn()}
|
111
|
+
conversations={initialConversations}
|
112
|
+
/>
|
113
|
+
);
|
114
|
+
|
115
|
+
fireEvent.keyDown(screen.getByPlaceholderText(/Search/i), {
|
116
|
+
key: 'Escape',
|
117
|
+
code: 'Escape',
|
118
|
+
keyCode: 27,
|
119
|
+
charCode: 27
|
120
|
+
});
|
121
|
+
|
122
|
+
waitFor(() => {
|
123
|
+
expect(screen.queryByText('Lightspeed documentation')).not.toBeInTheDocument();
|
124
|
+
});
|
125
|
+
});
|
126
|
+
});
|
@@ -72,6 +72,10 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
72
72
|
handleTextInputChange?: (value: string) => void;
|
73
73
|
/** Display mode of chatbot */
|
74
74
|
displayMode: ChatbotDisplayMode;
|
75
|
+
/** Reverses the order of the drawer action buttons */
|
76
|
+
reverseButtonOrder?: boolean;
|
77
|
+
/** Custom test id for the drawer actions */
|
78
|
+
drawerActionsTestId?: string;
|
75
79
|
}
|
76
80
|
|
77
81
|
export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConversationHistoryNavProps> = ({
|
@@ -88,6 +92,8 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
88
92
|
searchInputAriaLabel = 'Filter menu items',
|
89
93
|
handleTextInputChange,
|
90
94
|
displayMode,
|
95
|
+
reverseButtonOrder = false,
|
96
|
+
drawerActionsTestId = 'chatbot-nav-drawer-actions',
|
91
97
|
...props
|
92
98
|
}: ChatbotConversationHistoryNavProps) => {
|
93
99
|
const drawerRef = React.useRef<HTMLDivElement>(null);
|
@@ -161,7 +167,10 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
161
167
|
const panelContent = (
|
162
168
|
<DrawerPanelContent focusTrap={{ enabled: true }} minSize="384px" maxSize="384px">
|
163
169
|
<DrawerHead>
|
164
|
-
<DrawerActions
|
170
|
+
<DrawerActions
|
171
|
+
data-testid={drawerActionsTestId}
|
172
|
+
className={reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : ''}
|
173
|
+
>
|
165
174
|
<DrawerCloseButton onClick={onDrawerToggle} />
|
166
175
|
{onNewChat && <Button onClick={onNewChat}>{newChatButtonText}</Button>}
|
167
176
|
</DrawerActions>
|