Skip to content

Commit 3a52a7e

Browse files
authored
feat(ChatbotHeaderNewChatButton): add new chat button (#626)
Also added icon to "New chat" button in history drawer.
1 parent 1b995f0 commit 3a52a7e

12 files changed

Lines changed: 185 additions & 61 deletions

File tree

package-lock.json

Lines changed: 49 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"@babel/preset-react": "^7.23.3",
4040
"@babel/preset-typescript": "^7.23.3",
4141
"@octokit/rest": "^18.0.0",
42-
"@patternfly/documentation-framework": "6.8.2",
42+
"@patternfly/documentation-framework": "6.16.0",
4343
"@patternfly/patternfly": "^6.1.0",
4444
"@patternfly/react-icons": "^6.1.0",
4545
"@patternfly/react-table": "^6.1.0",

packages/module/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"react-dom": "^17 || ^18 || ^19"
5353
},
5454
"devDependencies": {
55-
"@patternfly/documentation-framework": "6.8.2",
55+
"@patternfly/documentation-framework": "6.16.0",
5656
"@patternfly/patternfly": "^6.1.0",
5757
"@patternfly/patternfly-a11y": "^5.0.0",
5858
"@types/dom-speech-recognition": "^0.0.4",

packages/module/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderBasic.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import {
1717
ChatbotHeaderActions,
1818
ChatbotHeaderTitle,
1919
ChatbotHeaderOptionsDropdown,
20-
ChatbotHeaderSelectorDropdown
20+
ChatbotHeaderSelectorDropdown,
21+
ChatbotHeaderNewChatButton
2122
} from '@patternfly/chatbot/dist/dynamic/ChatbotHeader';
2223
import { ChatbotDisplayMode } from '@patternfly/chatbot/dist/dynamic/Chatbot';
2324
import OutlinedWindowRestoreIcon from '@patternfly/react-icons/dist/esm/icons/outlined-window-restore-icon';
@@ -31,6 +32,7 @@ export const BasicDemo: FunctionComponent = () => {
3132
const [selectedModel, setSelectedModel] = useState('Granite Code 7B');
3233
const [showAll, setShowAll] = useState<boolean>(true);
3334
const [showMenu, setShowMenu] = useState<boolean>(true);
35+
const [showNewChatButton, setShowNewChatButton] = useState<boolean>(true);
3436
const [showLogo, setShowLogo] = useState<boolean>(false);
3537
const [showCenteredLogo, setShowCenteredLogo] = useState<boolean>(true);
3638
const [showSelectorDropdown, setShowSelectorDropdown] = useState<boolean>(true);
@@ -58,9 +60,10 @@ export const BasicDemo: FunctionComponent = () => {
5860
<Stack hasGutter>
5961
<FormGroup role="radiogroup" isInline fieldId="header-variant-form-radio-group" label="Variant">
6062
<Checkbox
61-
isChecked={showMenu && showCenteredLogo && showSelectorDropdown && showOptionsDropdown}
63+
isChecked={showMenu && showNewChatButton && showCenteredLogo && showSelectorDropdown && showOptionsDropdown}
6264
onChange={() => {
6365
setShowMenu(true);
66+
setShowNewChatButton(true);
6467
setShowCenteredLogo(true);
6568
setShowSelectorDropdown(true);
6669
setShowOptionsDropdown(true);
@@ -80,6 +83,16 @@ export const BasicDemo: FunctionComponent = () => {
8083
label="With menu"
8184
id="menu"
8285
/>
86+
<Checkbox
87+
isChecked={showNewChatButton}
88+
onChange={() => {
89+
setShowNewChatButton(!showNewChatButton);
90+
showAll && setShowAll(!showAll);
91+
}}
92+
name="basic-inline-radio"
93+
label="With new chat button"
94+
id="new-chat-button"
95+
/>
8396
<Checkbox
8497
isChecked={showLogo}
8598
onChange={() => {
@@ -124,9 +137,10 @@ export const BasicDemo: FunctionComponent = () => {
124137
</FormGroup>
125138

126139
<ChatbotHeader>
127-
{(showMenu || showLogo || showCenteredLogo) && (
140+
{(showMenu || showNewChatButton || showLogo || showCenteredLogo) && (
128141
<ChatbotHeaderMain>
129142
{showMenu && <ChatbotHeaderMenu onMenuToggle={() => alert('Menu toggle clicked')} />}
143+
{showNewChatButton && <ChatbotHeaderNewChatButton onClick={() => alert('New chat button clicked')} />}
130144
{(showLogo || showCenteredLogo) && (
131145
<ChatbotHeaderTitle>{showCenteredLogo ? <Bullseye>{title}</Bullseye> : title}</ChatbotHeaderTitle>
132146
)}

packages/module/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ ChatbotHeaderMenu,
6161
ChatbotHeaderActions,
6262
ChatbotHeaderTitle,
6363
ChatbotHeaderOptionsDropdown,
64-
ChatbotHeaderSelectorDropdown
64+
ChatbotHeaderSelectorDropdown,
65+
ChatbotHeaderNewChatButton
6566
} from '@patternfly/chatbot/dist/dynamic/ChatbotHeader';
6667
import { ChatbotFooter, ChatbotFootnote } from '@patternfly/chatbot/dist/dynamic/ChatbotFooter';
6768
import { MessageBar } from '@patternfly/chatbot/dist/dynamic/MessageBar';
@@ -78,6 +79,7 @@ import OutlinedWindowRestoreIcon from '@patternfly/react-icons/dist/esm/icons/ou
7879
import ExpandIcon from '@patternfly/react-icons/dist/esm/icons/expand-icon';
7980
import OpenDrawerRightIcon from '@patternfly/react-icons/dist/esm/icons/open-drawer-right-icon';
8081
import CogIcon from '@patternfly/react-icons/dist/esm/icons/cog-icon';
82+
import PenToSquareIcon from '@patternfly/react-icons/dist/esm/icons/pen-to-square-icon';
8183
import PFHorizontalLogoColor from './PF-HorizontalLogo-Color.svg';
8284
import PFHorizontalLogoReverse from './PF-HorizontalLogo-Reverse.svg';
8385
import userAvatar from '../Messages/user_avatar.svg';
@@ -184,9 +186,10 @@ The ChatBot header is persistent, and contains the title for the ChatBot window,
184186

185187
The `<ChatbotHeader>` has 2 sections:
186188

187-
- `<ChatbotHeaderMain>` contains the title and an optional menu toggle:
189+
- `<ChatbotHeaderMain>` contains the title and an optional menu toggle or new chat button:
188190
- `<ChatbotHeaderTitle>` handles the layout and display of a title or image at different responsive sizes.
189191
- `<ChatbotHeaderMenu>` (optional) is placed on the left side of the header and used to toggle a chat history menu.
192+
- `<ChatbotHeaderNewChatButton>` (optional) is placed on the left side of the header and used to initiate a new chat.
190193
- `<ChatbotHeaderActions>` contains any additional controls:
191194
- The `<ChatbotHeaderSelectorDropdown>` component is a standard PatternFly dropdown that matches the ChatBot styles.
192195
- The `<ChatbotHeaderOptionsDropdown>` component is a dropdown with a menu toggle that is intended to be used to update ChatBot settings (like the display mode).
@@ -197,6 +200,7 @@ Your `<ChatbotHeader>` code structure should look like this:
197200
<ChatbotHeader>
198201
<ChatbotHeaderMain>
199202
<ChatbotHeaderMenu ... />
203+
<ChatbotHeaderNewChatButton ... />
200204
<ChatbotHeaderTitle ... />
201205
</ChatbotHeaderMain>
202206
<ChatbotHeaderActions>
@@ -221,6 +225,7 @@ There are a variety of options and customizations you can make to the header, to
221225
In this example, select the respective checkbox to toggle these features:
222226

223227
- **Menu:** Users can select the menu toggle to open a menu of additional options or actions.
228+
- **New chat button:** Used to start a new chat session. The header button can be used in addition to or in place of a new chat button within the [conversation history drawer](/patternfly-ai/chatbot/ui/#drawer-with-search-and-new-chat-button).
224229
- **Left-aligned logo**
225230
- **Centered logo**
226231
- **Selector dropdown:** Users can choose from preselected options in a dropdown menu. For example, they can toggle between AI models.

packages/module/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ ChatbotHeaderTitle,
4545
ChatbotHeaderActions,
4646
ChatbotHeaderSelectorDropdown,
4747
ChatbotHeaderOptionsDropdown,
48-
ChatbotHeaderCloseButton
48+
ChatbotHeaderCloseButton,
4949
} from '@patternfly/chatbot/dist/dynamic/ChatbotHeader';
5050

5151
import ExpandIcon from '@patternfly/react-icons/dist/esm/icons/expand-icon';

packages/module/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import {
3838
ButtonProps
3939
} from '@patternfly/react-core';
4040

41-
import { OutlinedClockIcon, OutlinedCommentAltIcon } from '@patternfly/react-icons';
41+
import { OutlinedClockIcon, OutlinedCommentAltIcon, PenToSquareIcon } from '@patternfly/react-icons';
4242
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
4343
import ConversationHistoryDropdown from './ChatbotConversationHistoryDropdown';
4444
import LoadingState from './LoadingState';
@@ -262,7 +262,12 @@ export const ChatbotConversationHistoryNav: FunctionComponent<ChatbotConversatio
262262
>
263263
<DrawerCloseButton onClick={onDrawerToggle} {...drawerCloseButtonProps} />
264264
{onNewChat && (
265-
<Button size={isCompact ? 'sm' : undefined} onClick={onNewChat} {...newChatButtonProps}>
265+
<Button
266+
size={isCompact ? 'sm' : undefined}
267+
onClick={onNewChat}
268+
icon={<PenToSquareIcon />}
269+
{...newChatButtonProps}
270+
>
266271
{newChatButtonText}
267272
</Button>
268273
)}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { fireEvent, render, screen } from '@testing-library/react';
2+
import { ChatbotHeaderNewChatButton } from './ChatbotHeaderNewChatButton';
3+
import '@testing-library/jest-dom';
4+
5+
describe('ChatbotHeaderNewChatButton', () => {
6+
it('should render ChatbotHeaderNewChatButton', () => {
7+
const { container } = render(
8+
<ChatbotHeaderNewChatButton className="custom-header-new-chat-button" onClick={jest.fn()} />
9+
);
10+
11+
expect(container.querySelector('.custom-header-new-chat-button')).toBeTruthy();
12+
});
13+
14+
it('should call onClick handler when new chat button is pressed', () => {
15+
const onClick = jest.fn();
16+
render(<ChatbotHeaderNewChatButton className="custom-header-new-chat-button" onClick={onClick} />);
17+
fireEvent.click(screen.getByRole('button', { name: 'New chat' }));
18+
expect(onClick).toHaveBeenCalled();
19+
});
20+
21+
it('should render button with isCompact', () => {
22+
render(<ChatbotHeaderNewChatButton data-testid="new-chat-button" onClick={jest.fn()} isCompact />);
23+
expect(screen.getByTestId('new-chat-button')).toHaveClass('pf-m-compact');
24+
});
25+
});

0 commit comments

Comments
 (0)