@patternfly/chatbot 6.4.0-prerelease.6 → 6.4.0-prerelease.8
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.d.ts +2 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +5 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +3 -3
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +4 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +2 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +2 -2
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +5 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +3 -3
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +4 -0
- package/package.json +4 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx +12 -2
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +5 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +16 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +9 -1
|
@@ -9,6 +9,8 @@ export interface ChatbotConversationHistoryDropdownProps extends Omit<DropdownPr
|
|
|
9
9
|
label?: string;
|
|
10
10
|
/** Callback for when user selects item. */
|
|
11
11
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
12
|
+
/** Id applied to dropdown menu toggle */
|
|
13
|
+
id?: string;
|
|
12
14
|
}
|
|
13
15
|
export declare const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConversationHistoryDropdownProps>;
|
|
14
16
|
export default ChatbotConversationHistoryDropdown;
|
|
@@ -9,11 +9,11 @@ const react_1 = require("react");
|
|
|
9
9
|
// Import PatternFly components
|
|
10
10
|
const react_core_1 = require("@patternfly/react-core");
|
|
11
11
|
const ellipsis_v_icon_1 = __importDefault(require("@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon"));
|
|
12
|
-
const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label }) => {
|
|
12
|
+
const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label, id }) => {
|
|
13
13
|
const [isOpen, setIsOpen] = (0, react_1.useState)(false);
|
|
14
14
|
const toggle = (toggleRef) => ((0, jsx_runtime_1.jsx)(react_core_1.Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom",
|
|
15
15
|
// prevents VO announcements of both aria label and tooltip
|
|
16
|
-
aria: "none", children: (0, jsx_runtime_1.jsx)(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), children: (0, jsx_runtime_1.jsx)(ellipsis_v_icon_1.default, {}) }) }));
|
|
16
|
+
aria: "none", children: (0, jsx_runtime_1.jsx)(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), id: id, children: (0, jsx_runtime_1.jsx)(ellipsis_v_icon_1.default, {}) }) }));
|
|
17
17
|
return ((0, jsx_runtime_1.jsx)(react_core_1.Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
|
|
18
18
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
|
19
19
|
setIsOpen((prev) => !prev);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'react';
|
|
2
2
|
import { ButtonProps, DrawerProps, ListItemProps, DrawerPanelContentProps, DrawerContentProps, DrawerContentBodyProps, DrawerHeadProps, DrawerActionsProps, DrawerCloseButtonProps, DrawerPanelBodyProps, SkeletonProps, MenuProps, // Remove in next breaking change
|
|
3
|
-
TitleProps, ListProps } from '@patternfly/react-core';
|
|
3
|
+
TitleProps, ListProps, SearchInputProps } from '@patternfly/react-core';
|
|
4
4
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
|
5
5
|
import { HistoryEmptyStateProps } from './EmptyState';
|
|
6
6
|
export interface Conversation {
|
|
@@ -24,6 +24,8 @@ export interface Conversation {
|
|
|
24
24
|
additionalProps?: ButtonProps;
|
|
25
25
|
/** Additional props passed to conversation list item */
|
|
26
26
|
listItemProps?: Omit<ListItemProps, 'children'>;
|
|
27
|
+
/** Custom dropdown ID to ensure uniqueness across demo instances */
|
|
28
|
+
dropdownId?: string;
|
|
27
29
|
}
|
|
28
30
|
export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
29
31
|
/** Function called to toggle drawer */
|
|
@@ -57,6 +59,8 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
57
59
|
searchInputPlaceholder?: string;
|
|
58
60
|
/** Aria label for search input */
|
|
59
61
|
searchInputAriaLabel?: string;
|
|
62
|
+
/** Additional props passed to search input */
|
|
63
|
+
searchInputProps?: SearchInputProps;
|
|
60
64
|
/** A callback for when the input value changes. Omit to hide input field */
|
|
61
65
|
handleTextInputChange?: (value: string) => void;
|
|
62
66
|
/** Display mode of chatbot */
|
|
@@ -25,14 +25,14 @@ const ChatbotConversationHistoryDropdown_1 = __importDefault(require("./ChatbotC
|
|
|
25
25
|
const LoadingState_1 = __importDefault(require("./LoadingState"));
|
|
26
26
|
const EmptyState_1 = __importDefault(require("./EmptyState"));
|
|
27
27
|
const ChatbotConversationHistoryNav = (_a) => {
|
|
28
|
-
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, titleProps, listProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "titleProps", "listProps", "newChatButtonText", "drawerContent", "onNewChat", "newChatButtonProps", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId", "drawerPanelContentProps", "drawerContentProps", "drawerContentBodyProps", "drawerHeadProps", "drawerActionsProps", "drawerCloseButtonProps", "drawerPanelBodyProps", "isLoading", "loadingState", "errorState", "emptyState", "noResultsState", "isCompact", "title"]);
|
|
28
|
+
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, titleProps, listProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Filter menu items', searchInputProps, handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "titleProps", "listProps", "newChatButtonText", "drawerContent", "onNewChat", "newChatButtonProps", "searchInputPlaceholder", "searchInputAriaLabel", "searchInputProps", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId", "drawerPanelContentProps", "drawerContentProps", "drawerContentBodyProps", "drawerHeadProps", "drawerActionsProps", "drawerCloseButtonProps", "drawerPanelBodyProps", "isLoading", "loadingState", "errorState", "emptyState", "noResultsState", "isCompact", "title"]);
|
|
29
29
|
const drawerRef = (0, react_1.useRef)(null);
|
|
30
30
|
const onExpand = () => {
|
|
31
31
|
drawerRef.current && drawerRef.current.focus();
|
|
32
32
|
};
|
|
33
33
|
const getNavItem = (conversation) => {
|
|
34
34
|
var _a;
|
|
35
|
-
return ((0, jsx_runtime_1.jsx)(react_core_1.ListItem, Object.assign({ className: `pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}` }, conversation.listItemProps, { children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: "pf-chatbot__conversation-history-item", variant: "link" }, conversation.additionalProps, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedCommentAltIcon, {}) }), { onClick: (event) => onSelectActiveItem === null || onSelectActiveItem === void 0 ? void 0 : onSelectActiveItem(event, conversation.id), children: conversation.text })), conversation.menuItems && ((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryDropdown_1.default, { menuClassName: conversation.menuClassName, onSelect: conversation.onSelect, menuItems: conversation.menuItems, label: conversation.label }))] }) }), conversation.id));
|
|
35
|
+
return ((0, jsx_runtime_1.jsx)(react_core_1.ListItem, Object.assign({ className: `pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}` }, conversation.listItemProps, { children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ className: "pf-chatbot__conversation-history-item", variant: "link" }, conversation.additionalProps, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedCommentAltIcon, {}) }), { onClick: (event) => onSelectActiveItem === null || onSelectActiveItem === void 0 ? void 0 : onSelectActiveItem(event, conversation.id), children: conversation.text })), conversation.menuItems && ((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryDropdown_1.default, { menuClassName: conversation.menuClassName, onSelect: conversation.onSelect, menuItems: conversation.menuItems, label: conversation.label, id: conversation.dropdownId }))] }) }), conversation.id));
|
|
36
36
|
};
|
|
37
37
|
const buildConversations = () => {
|
|
38
38
|
if (Array.isArray(conversations)) {
|
|
@@ -59,7 +59,7 @@ const ChatbotConversationHistoryNav = (_a) => {
|
|
|
59
59
|
};
|
|
60
60
|
const renderDrawerContent = () => ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(react_core_1.DrawerPanelBody, Object.assign({}, drawerPanelBodyProps, { children: renderMenuContent() })) }));
|
|
61
61
|
const renderPanelContent = () => {
|
|
62
|
-
const drawer = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerHead, Object.assign({}, drawerHeadProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: (0, jsx_runtime_1.jsx)(react_icons_1.PenToSquareIcon, {}) }, newChatButtonProps, { children: newChatButtonText })))] })) })), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__title-container", children: [(0, jsx_runtime_1.jsxs)(react_core_1.Title, { headingLevel: "h3", children: [(0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: "lg", className: "pf-chatbot__title-icon", children: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedClockIcon, {}) }), title] }), !isLoading && handleTextInputChange && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__input", children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, { "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }) }))] }), isLoading ? (0, jsx_runtime_1.jsx)(LoadingState_1.default, Object.assign({}, loadingState)) : renderDrawerContent()] }));
|
|
62
|
+
const drawer = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerHead, Object.assign({}, drawerHeadProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [(0, jsx_runtime_1.jsx)(react_core_1.DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && ((0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: (0, jsx_runtime_1.jsx)(react_icons_1.PenToSquareIcon, {}) }, newChatButtonProps, { children: newChatButtonText })))] })) })), (0, jsx_runtime_1.jsxs)("div", { className: "pf-chatbot__title-container", children: [(0, jsx_runtime_1.jsxs)(react_core_1.Title, { headingLevel: "h3", children: [(0, jsx_runtime_1.jsx)(react_core_1.Icon, { size: "lg", className: "pf-chatbot__title-icon", children: (0, jsx_runtime_1.jsx)(react_icons_1.OutlinedClockIcon, {}) }), title] }), !isLoading && handleTextInputChange && ((0, jsx_runtime_1.jsx)("div", { className: "pf-chatbot__input", children: (0, jsx_runtime_1.jsx)(react_core_1.SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) }))] }), isLoading ? (0, jsx_runtime_1.jsx)(LoadingState_1.default, Object.assign({}, loadingState)) : renderDrawerContent()] }));
|
|
63
63
|
return ((0, jsx_runtime_1.jsx)(react_core_1.DrawerPanelContent, Object.assign({ "aria-live": "polite", focusTrap: { enabled: true }, defaultSize: "384px" }, drawerPanelContentProps, { children: drawer })));
|
|
64
64
|
};
|
|
65
65
|
// An onKeyDown property must be passed to the Drawer component to handle closing
|
|
@@ -219,4 +219,8 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
219
219
|
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: [{ id: '1', text: 'ChatBot documentation', listItemProps: { className: 'test' } }] }));
|
|
220
220
|
expect(react_1.screen.getByRole('listitem')).toHaveClass('test');
|
|
221
221
|
});
|
|
222
|
+
it('should be able to spread search input props when searchInputProps is passed', () => {
|
|
223
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(ChatbotConversationHistoryNav_1.default, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: Chatbot_1.ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: initialConversations, handleTextInputChange: jest.fn(), searchInputProps: { value: 'I am a sample search' } }));
|
|
224
|
+
expect(react_1.screen.getByRole('dialog', { name: /Chat history I am a sample search/i })).toBeInTheDocument();
|
|
225
|
+
});
|
|
222
226
|
});
|
|
@@ -9,6 +9,8 @@ export interface ChatbotConversationHistoryDropdownProps extends Omit<DropdownPr
|
|
|
9
9
|
label?: string;
|
|
10
10
|
/** Callback for when user selects item. */
|
|
11
11
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
12
|
+
/** Id applied to dropdown menu toggle */
|
|
13
|
+
id?: string;
|
|
12
14
|
}
|
|
13
15
|
export declare const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConversationHistoryDropdownProps>;
|
|
14
16
|
export default ChatbotConversationHistoryDropdown;
|
|
@@ -3,11 +3,11 @@ import { useState } from 'react';
|
|
|
3
3
|
// Import PatternFly components
|
|
4
4
|
import { Tooltip, MenuToggle, Dropdown } from '@patternfly/react-core';
|
|
5
5
|
import EllipsisIcon from '@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
|
|
6
|
-
export const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label }) => {
|
|
6
|
+
export const ChatbotConversationHistoryDropdown = ({ menuItems, menuClassName, onSelect, label, id }) => {
|
|
7
7
|
const [isOpen, setIsOpen] = useState(false);
|
|
8
8
|
const toggle = (toggleRef) => (_jsx(Tooltip, { className: "pf-chatbot__tooltip", content: label !== null && label !== void 0 ? label : 'Conversation options', position: "bottom",
|
|
9
9
|
// prevents VO announcements of both aria label and tooltip
|
|
10
|
-
aria: "none", children: _jsx(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), children: _jsx(EllipsisIcon, {}) }) }));
|
|
10
|
+
aria: "none", children: _jsx(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), id: id, children: _jsx(EllipsisIcon, {}) }) }));
|
|
11
11
|
return (_jsx(Dropdown, { className: `pf-chatbot__selections ${menuClassName !== null && menuClassName !== void 0 ? menuClassName : ''}`, isOpen: isOpen, onSelect: (props) => {
|
|
12
12
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(props);
|
|
13
13
|
setIsOpen((prev) => !prev);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'react';
|
|
2
2
|
import { ButtonProps, DrawerProps, ListItemProps, DrawerPanelContentProps, DrawerContentProps, DrawerContentBodyProps, DrawerHeadProps, DrawerActionsProps, DrawerCloseButtonProps, DrawerPanelBodyProps, SkeletonProps, MenuProps, // Remove in next breaking change
|
|
3
|
-
TitleProps, ListProps } from '@patternfly/react-core';
|
|
3
|
+
TitleProps, ListProps, SearchInputProps } from '@patternfly/react-core';
|
|
4
4
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
|
5
5
|
import { HistoryEmptyStateProps } from './EmptyState';
|
|
6
6
|
export interface Conversation {
|
|
@@ -24,6 +24,8 @@ export interface Conversation {
|
|
|
24
24
|
additionalProps?: ButtonProps;
|
|
25
25
|
/** Additional props passed to conversation list item */
|
|
26
26
|
listItemProps?: Omit<ListItemProps, 'children'>;
|
|
27
|
+
/** Custom dropdown ID to ensure uniqueness across demo instances */
|
|
28
|
+
dropdownId?: string;
|
|
27
29
|
}
|
|
28
30
|
export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
29
31
|
/** Function called to toggle drawer */
|
|
@@ -57,6 +59,8 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
57
59
|
searchInputPlaceholder?: string;
|
|
58
60
|
/** Aria label for search input */
|
|
59
61
|
searchInputAriaLabel?: string;
|
|
62
|
+
/** Additional props passed to search input */
|
|
63
|
+
searchInputProps?: SearchInputProps;
|
|
60
64
|
/** A callback for when the input value changes. Omit to hide input field */
|
|
61
65
|
handleTextInputChange?: (value: string) => void;
|
|
62
66
|
/** Display mode of chatbot */
|
|
@@ -19,14 +19,14 @@ import ConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
|
|
|
19
19
|
import LoadingState from './LoadingState';
|
|
20
20
|
import HistoryEmptyState from './EmptyState';
|
|
21
21
|
export const ChatbotConversationHistoryNav = (_a) => {
|
|
22
|
-
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, titleProps, listProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Filter menu items', handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "titleProps", "listProps", "newChatButtonText", "drawerContent", "onNewChat", "newChatButtonProps", "searchInputPlaceholder", "searchInputAriaLabel", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId", "drawerPanelContentProps", "drawerContentProps", "drawerContentBodyProps", "drawerHeadProps", "drawerActionsProps", "drawerCloseButtonProps", "drawerPanelBodyProps", "isLoading", "loadingState", "errorState", "emptyState", "noResultsState", "isCompact", "title"]);
|
|
22
|
+
var { onDrawerToggle, isDrawerOpen, setIsDrawerOpen, activeItemId, onSelectActiveItem, conversations, titleProps, listProps, newChatButtonText = 'New chat', drawerContent, onNewChat, newChatButtonProps, searchInputPlaceholder = 'Search previous conversations...', searchInputAriaLabel = 'Filter menu items', searchInputProps, handleTextInputChange, displayMode, reverseButtonOrder = false, drawerActionsTestId = 'chatbot-nav-drawer-actions', drawerPanelContentProps, drawerContentProps, drawerContentBodyProps, drawerHeadProps, drawerActionsProps, drawerCloseButtonProps, drawerPanelBodyProps, isLoading, loadingState, errorState, emptyState, noResultsState, isCompact, title = 'Chat history' } = _a, props = __rest(_a, ["onDrawerToggle", "isDrawerOpen", "setIsDrawerOpen", "activeItemId", "onSelectActiveItem", "conversations", "titleProps", "listProps", "newChatButtonText", "drawerContent", "onNewChat", "newChatButtonProps", "searchInputPlaceholder", "searchInputAriaLabel", "searchInputProps", "handleTextInputChange", "displayMode", "reverseButtonOrder", "drawerActionsTestId", "drawerPanelContentProps", "drawerContentProps", "drawerContentBodyProps", "drawerHeadProps", "drawerActionsProps", "drawerCloseButtonProps", "drawerPanelBodyProps", "isLoading", "loadingState", "errorState", "emptyState", "noResultsState", "isCompact", "title"]);
|
|
23
23
|
const drawerRef = useRef(null);
|
|
24
24
|
const onExpand = () => {
|
|
25
25
|
drawerRef.current && drawerRef.current.focus();
|
|
26
26
|
};
|
|
27
27
|
const getNavItem = (conversation) => {
|
|
28
28
|
var _a;
|
|
29
|
-
return (_jsx(ListItem, Object.assign({ className: `pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}` }, conversation.listItemProps, { children: _jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ className: "pf-chatbot__conversation-history-item", variant: "link" }, conversation.additionalProps, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : _jsx(OutlinedCommentAltIcon, {}) }), { onClick: (event) => onSelectActiveItem === null || onSelectActiveItem === void 0 ? void 0 : onSelectActiveItem(event, conversation.id), children: conversation.text })), conversation.menuItems && (_jsx(ConversationHistoryDropdown, { menuClassName: conversation.menuClassName, onSelect: conversation.onSelect, menuItems: conversation.menuItems, label: conversation.label }))] }) }), conversation.id));
|
|
29
|
+
return (_jsx(ListItem, Object.assign({ className: `pf-chatbot__conversation-list-item ${activeItemId && activeItemId === conversation.id ? 'pf-chatbot__conversation-list-item--active' : ''}` }, conversation.listItemProps, { children: _jsxs(_Fragment, { children: [_jsx(Button, Object.assign({ className: "pf-chatbot__conversation-history-item", variant: "link" }, conversation.additionalProps, (conversation.noIcon ? {} : { icon: (_a = conversation.icon) !== null && _a !== void 0 ? _a : _jsx(OutlinedCommentAltIcon, {}) }), { onClick: (event) => onSelectActiveItem === null || onSelectActiveItem === void 0 ? void 0 : onSelectActiveItem(event, conversation.id), children: conversation.text })), conversation.menuItems && (_jsx(ConversationHistoryDropdown, { menuClassName: conversation.menuClassName, onSelect: conversation.onSelect, menuItems: conversation.menuItems, label: conversation.label, id: conversation.dropdownId }))] }) }), conversation.id));
|
|
30
30
|
};
|
|
31
31
|
const buildConversations = () => {
|
|
32
32
|
if (Array.isArray(conversations)) {
|
|
@@ -53,7 +53,7 @@ export const ChatbotConversationHistoryNav = (_a) => {
|
|
|
53
53
|
};
|
|
54
54
|
const renderDrawerContent = () => (_jsx(_Fragment, { children: _jsx(DrawerPanelBody, Object.assign({}, drawerPanelBodyProps, { children: renderMenuContent() })) }));
|
|
55
55
|
const renderPanelContent = () => {
|
|
56
|
-
const drawer = (_jsxs(_Fragment, { children: [_jsx(DrawerHead, Object.assign({}, drawerHeadProps, { children: _jsxs(DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [_jsx(DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && (_jsx(Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: _jsx(PenToSquareIcon, {}) }, newChatButtonProps, { children: newChatButtonText })))] })) })), _jsxs("div", { className: "pf-chatbot__title-container", children: [_jsxs(Title, { headingLevel: "h3", children: [_jsx(Icon, { size: "lg", className: "pf-chatbot__title-icon", children: _jsx(OutlinedClockIcon, {}) }), title] }), !isLoading && handleTextInputChange && (_jsx("div", { className: "pf-chatbot__input", children: _jsx(SearchInput, { "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }) }))] }), isLoading ? _jsx(LoadingState, Object.assign({}, loadingState)) : renderDrawerContent()] }));
|
|
56
|
+
const drawer = (_jsxs(_Fragment, { children: [_jsx(DrawerHead, Object.assign({}, drawerHeadProps, { children: _jsxs(DrawerActions, Object.assign({ "data-testid": drawerActionsTestId, className: reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : '' }, drawerActionsProps, { children: [_jsx(DrawerCloseButton, Object.assign({ onClick: onDrawerToggle }, drawerCloseButtonProps)), onNewChat && (_jsx(Button, Object.assign({ size: isCompact ? 'sm' : undefined, onClick: onNewChat, icon: _jsx(PenToSquareIcon, {}) }, newChatButtonProps, { children: newChatButtonText })))] })) })), _jsxs("div", { className: "pf-chatbot__title-container", children: [_jsxs(Title, { headingLevel: "h3", children: [_jsx(Icon, { size: "lg", className: "pf-chatbot__title-icon", children: _jsx(OutlinedClockIcon, {}) }), title] }), !isLoading && handleTextInputChange && (_jsx("div", { className: "pf-chatbot__input", children: _jsx(SearchInput, Object.assign({ "aria-label": searchInputAriaLabel, onChange: (_event, value) => handleTextInputChange(value), placeholder: searchInputPlaceholder }, searchInputProps)) }))] }), isLoading ? _jsx(LoadingState, Object.assign({}, loadingState)) : renderDrawerContent()] }));
|
|
57
57
|
return (_jsx(DrawerPanelContent, Object.assign({ "aria-live": "polite", focusTrap: { enabled: true }, defaultSize: "384px" }, drawerPanelContentProps, { children: drawer })));
|
|
58
58
|
};
|
|
59
59
|
// An onKeyDown property must be passed to the Drawer component to handle closing
|
|
@@ -214,4 +214,8 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
214
214
|
render(_jsx(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: [{ id: '1', text: 'ChatBot documentation', listItemProps: { className: 'test' } }] }));
|
|
215
215
|
expect(screen.getByRole('listitem')).toHaveClass('test');
|
|
216
216
|
});
|
|
217
|
+
it('should be able to spread search input props when searchInputProps is passed', () => {
|
|
218
|
+
render(_jsx(ChatbotConversationHistoryNav, { onDrawerToggle: onDrawerToggle, isDrawerOpen: true, displayMode: ChatbotDisplayMode.fullscreen, setIsDrawerOpen: jest.fn(), conversations: initialConversations, handleTextInputChange: jest.fn(), searchInputProps: { value: 'I am a sample search' } }));
|
|
219
|
+
expect(screen.getByRole('dialog', { name: /Chat history I am a sample search/i })).toBeInTheDocument();
|
|
220
|
+
});
|
|
217
221
|
});
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/chatbot",
|
|
3
|
-
"version": "6.4.0-prerelease.
|
|
3
|
+
"version": "6.4.0-prerelease.8",
|
|
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",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "
|
|
8
|
+
"build": "npm run build:css && npm run build:index && npm run build:js && npm run build:esm && npm run build:fed:packages",
|
|
9
9
|
"build:watch": "npm run build:js && npm run build:esm -- --watch && npm run build:fed:packages -- --watch",
|
|
10
10
|
"build:esm": "tsc --build --verbose ./tsconfig.json",
|
|
11
11
|
"build:fed:packages": "node generate-fed-package-json.js",
|
|
12
12
|
"build:js": "tsc -p tsconfig.cjs.json",
|
|
13
13
|
"build:index": "node generate-index.js",
|
|
14
|
+
"build:css": "sass src/main.scss dist/css/main.css",
|
|
15
|
+
"build:css:watch": "sass src/main.scss dist/css/main.css --watch",
|
|
14
16
|
"clean": "rimraf dist",
|
|
15
17
|
"docs:develop": "pf-docs-framework start",
|
|
16
18
|
"docs:build": "pf-docs-framework build all --output public",
|
package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithPin.tsx
CHANGED
|
@@ -97,6 +97,14 @@ export const ChatbotHeaderPinDemo: FunctionComponent = () => {
|
|
|
97
97
|
}
|
|
98
98
|
return newPinned;
|
|
99
99
|
});
|
|
100
|
+
|
|
101
|
+
// Focus the conversation input after pin/unpin action
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
const dropdown = document.getElementById(`pin-demo-${conversationId}-dropdown`);
|
|
104
|
+
if (dropdown) {
|
|
105
|
+
dropdown.focus();
|
|
106
|
+
}
|
|
107
|
+
}, 100);
|
|
100
108
|
};
|
|
101
109
|
|
|
102
110
|
const createMenuItems = (conversationId: string) => {
|
|
@@ -136,7 +144,8 @@ export const ChatbotHeaderPinDemo: FunctionComponent = () => {
|
|
|
136
144
|
pinnedItems.push({
|
|
137
145
|
...conv,
|
|
138
146
|
menuItems: createMenuItems(conv.id),
|
|
139
|
-
icon: <ThumbtackIcon
|
|
147
|
+
icon: <ThumbtackIcon />,
|
|
148
|
+
dropdownId: `pin-demo-${conv.id}-dropdown`
|
|
140
149
|
});
|
|
141
150
|
}
|
|
142
151
|
});
|
|
@@ -153,7 +162,8 @@ export const ChatbotHeaderPinDemo: FunctionComponent = () => {
|
|
|
153
162
|
.filter((conv) => !pinnedConversations.has(conv.id))
|
|
154
163
|
.map((conv) => ({
|
|
155
164
|
...conv,
|
|
156
|
-
menuItems: createMenuItems(conv.id)
|
|
165
|
+
menuItems: createMenuItems(conv.id),
|
|
166
|
+
dropdownId: `pin-demo-${conv.id}-dropdown`
|
|
157
167
|
}));
|
|
158
168
|
|
|
159
169
|
if (unpinnedConversations.length > 0) {
|
|
@@ -19,13 +19,16 @@ export interface ChatbotConversationHistoryDropdownProps extends Omit<DropdownPr
|
|
|
19
19
|
label?: string;
|
|
20
20
|
/** Callback for when user selects item. */
|
|
21
21
|
onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
|
|
22
|
+
/** Id applied to dropdown menu toggle */
|
|
23
|
+
id?: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConversationHistoryDropdownProps> = ({
|
|
25
27
|
menuItems,
|
|
26
28
|
menuClassName,
|
|
27
29
|
onSelect,
|
|
28
|
-
label
|
|
30
|
+
label,
|
|
31
|
+
id
|
|
29
32
|
}: ChatbotConversationHistoryDropdownProps) => {
|
|
30
33
|
const [isOpen, setIsOpen] = useState(false);
|
|
31
34
|
|
|
@@ -44,6 +47,7 @@ export const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConver
|
|
|
44
47
|
ref={toggleRef}
|
|
45
48
|
isExpanded={isOpen}
|
|
46
49
|
onClick={() => setIsOpen(!isOpen)}
|
|
50
|
+
id={id}
|
|
47
51
|
>
|
|
48
52
|
<EllipsisIcon />
|
|
49
53
|
</MenuToggle>
|
|
@@ -561,4 +561,20 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
|
561
561
|
);
|
|
562
562
|
expect(screen.getByRole('listitem')).toHaveClass('test');
|
|
563
563
|
});
|
|
564
|
+
|
|
565
|
+
it('should be able to spread search input props when searchInputProps is passed', () => {
|
|
566
|
+
render(
|
|
567
|
+
<ChatbotConversationHistoryNav
|
|
568
|
+
onDrawerToggle={onDrawerToggle}
|
|
569
|
+
isDrawerOpen={true}
|
|
570
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
|
571
|
+
setIsDrawerOpen={jest.fn()}
|
|
572
|
+
conversations={initialConversations}
|
|
573
|
+
handleTextInputChange={jest.fn()}
|
|
574
|
+
searchInputProps={{ value: 'I am a sample search' }}
|
|
575
|
+
/>
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
expect(screen.getByRole('dialog', { name: /Chat history I am a sample search/i })).toBeInTheDocument();
|
|
579
|
+
});
|
|
564
580
|
});
|
|
@@ -34,7 +34,8 @@ import {
|
|
|
34
34
|
Icon,
|
|
35
35
|
MenuProps, // Remove in next breaking change
|
|
36
36
|
TitleProps,
|
|
37
|
-
ListProps
|
|
37
|
+
ListProps,
|
|
38
|
+
SearchInputProps
|
|
38
39
|
} from '@patternfly/react-core';
|
|
39
40
|
|
|
40
41
|
import { OutlinedClockIcon, OutlinedCommentAltIcon, PenToSquareIcon } from '@patternfly/react-icons';
|
|
@@ -64,6 +65,8 @@ export interface Conversation {
|
|
|
64
65
|
additionalProps?: ButtonProps;
|
|
65
66
|
/** Additional props passed to conversation list item */
|
|
66
67
|
listItemProps?: Omit<ListItemProps, 'children'>;
|
|
68
|
+
/** Custom dropdown ID to ensure uniqueness across demo instances */
|
|
69
|
+
dropdownId?: string;
|
|
67
70
|
}
|
|
68
71
|
export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
69
72
|
/** Function called to toggle drawer */
|
|
@@ -94,6 +97,8 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
|
94
97
|
searchInputPlaceholder?: string;
|
|
95
98
|
/** Aria label for search input */
|
|
96
99
|
searchInputAriaLabel?: string;
|
|
100
|
+
/** Additional props passed to search input */
|
|
101
|
+
searchInputProps?: SearchInputProps;
|
|
97
102
|
/** A callback for when the input value changes. Omit to hide input field */
|
|
98
103
|
handleTextInputChange?: (value: string) => void;
|
|
99
104
|
/** Display mode of chatbot */
|
|
@@ -149,6 +154,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
149
154
|
newChatButtonProps,
|
|
150
155
|
searchInputPlaceholder = 'Search previous conversations...',
|
|
151
156
|
searchInputAriaLabel = 'Filter menu items',
|
|
157
|
+
searchInputProps,
|
|
152
158
|
handleTextInputChange,
|
|
153
159
|
displayMode,
|
|
154
160
|
reverseButtonOrder = false,
|
|
@@ -198,6 +204,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
198
204
|
onSelect={conversation.onSelect}
|
|
199
205
|
menuItems={conversation.menuItems}
|
|
200
206
|
label={conversation.label}
|
|
207
|
+
id={conversation.dropdownId}
|
|
201
208
|
/>
|
|
202
209
|
)}
|
|
203
210
|
</>
|
|
@@ -292,6 +299,7 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
|
|
|
292
299
|
aria-label={searchInputAriaLabel}
|
|
293
300
|
onChange={(_event, value) => handleTextInputChange(value)}
|
|
294
301
|
placeholder={searchInputPlaceholder}
|
|
302
|
+
{...searchInputProps}
|
|
295
303
|
/>
|
|
296
304
|
</div>
|
|
297
305
|
)}
|