@patternfly/chatbot 2.2.0-prerelease.10 → 2.2.0-prerelease.11
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/ChatbotConversationHistoryNav.d.ts +15 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +8 -8
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +36 -0
- package/dist/cjs/Compare/Compare.d.ts +17 -0
- package/dist/cjs/Compare/Compare.js +50 -0
- package/dist/cjs/Compare/Compare.test.d.ts +1 -0
- package/dist/cjs/Compare/Compare.test.js +20 -0
- package/dist/cjs/Compare/index.d.ts +2 -0
- package/dist/cjs/Compare/index.js +23 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -1
- package/dist/css/main.css +75 -0
- package/dist/css/main.css.map +1 -1
- package/dist/dynamic/Compare/package.json +1 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +15 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +8 -8
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +36 -0
- package/dist/esm/Compare/Compare.d.ts +17 -0
- package/dist/esm/Compare/Compare.js +43 -0
- package/dist/esm/Compare/Compare.test.d.ts +1 -0
- package/dist/esm/Compare/Compare.test.js +15 -0
- package/dist/esm/Compare/index.d.ts +2 -0
- package/dist/esm/Compare/index.js +2 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx +94 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +10 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +24 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedComparisonChatbot.tsx +206 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +109 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +36 -7
- package/src/Compare/Compare.scss +72 -0
- package/src/Compare/Compare.test.tsx +31 -0
- package/src/Compare/Compare.tsx +98 -0
- package/src/Compare/index.ts +2 -0
- package/src/index.ts +3 -0
- package/src/main.scss +1 -0
package/dist/esm/index.d.ts
CHANGED
@@ -24,6 +24,8 @@ export { default as ChatbotWelcomePrompt } from './ChatbotWelcomePrompt';
|
|
24
24
|
export * from './ChatbotWelcomePrompt';
|
25
25
|
export { default as CodeModal } from './CodeModal';
|
26
26
|
export * from './CodeModal';
|
27
|
+
export { default as Compare } from './Compare';
|
28
|
+
export * from './Compare';
|
27
29
|
export { default as FileDetails } from './FileDetails';
|
28
30
|
export * from './FileDetails';
|
29
31
|
export { default as FileDetailsLabel } from './FileDetailsLabel';
|
package/dist/esm/index.js
CHANGED
@@ -25,6 +25,8 @@ export { default as ChatbotWelcomePrompt } from './ChatbotWelcomePrompt';
|
|
25
25
|
export * from './ChatbotWelcomePrompt';
|
26
26
|
export { default as CodeModal } from './CodeModal';
|
27
27
|
export * from './CodeModal';
|
28
|
+
export { default as Compare } from './Compare';
|
29
|
+
export * from './Compare';
|
28
30
|
export { default as FileDetails } from './FileDetails';
|
29
31
|
export * from './FileDetails';
|
30
32
|
export { default as FileDetailsLabel } from './FileDetailsLabel';
|
@@ -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.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/ChatbotHeaderCloseButton.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/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../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.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/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/ChatbotHeaderCloseButton.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/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/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/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../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.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts"],"version":"5.6.3"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@patternfly/chatbot",
|
3
|
-
"version": "2.2.0-prerelease.
|
3
|
+
"version": "2.2.0-prerelease.11",
|
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",
|
package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { ChatbotDisplayMode } from '@patternfly/chatbot/dist/dynamic/Chatbot';
|
3
|
+
import ChatbotConversationHistoryNav, {
|
4
|
+
Conversation
|
5
|
+
} from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
|
6
|
+
import { Checkbox } from '@patternfly/react-core';
|
7
|
+
|
8
|
+
const initialConversations: { [key: string]: Conversation[] } = {
|
9
|
+
Today: [{ id: '1', text: 'Red Hat products and services' }],
|
10
|
+
'This month': [
|
11
|
+
{
|
12
|
+
id: '2',
|
13
|
+
text: 'Enterprise Linux installation and setup'
|
14
|
+
},
|
15
|
+
{ id: '3', text: 'Troubleshoot system crash' }
|
16
|
+
],
|
17
|
+
March: [
|
18
|
+
{ id: '4', text: 'Ansible security and updates' },
|
19
|
+
{ id: '5', text: 'Red Hat certification' },
|
20
|
+
{ id: '6', text: 'Lightspeed user documentation' }
|
21
|
+
],
|
22
|
+
February: [
|
23
|
+
{ id: '7', text: 'Crashing pod assistance' },
|
24
|
+
{ id: '8', text: 'OpenShift AI pipelines' },
|
25
|
+
{ id: '9', text: 'Updating subscription plan' },
|
26
|
+
{ id: '10', text: 'Red Hat licensing options' }
|
27
|
+
],
|
28
|
+
January: [
|
29
|
+
{ id: '11', text: 'RHEL system performance' },
|
30
|
+
{ id: '12', text: 'Manage user accounts' }
|
31
|
+
]
|
32
|
+
};
|
33
|
+
|
34
|
+
export const ChatbotHeaderDrawerResizableDemo: React.FunctionComponent = () => {
|
35
|
+
const [isOpen, setIsOpen] = React.useState(true);
|
36
|
+
const [conversations, setConversations] = React.useState<Conversation[] | { [key: string]: Conversation[] }>(
|
37
|
+
initialConversations
|
38
|
+
);
|
39
|
+
const displayMode = ChatbotDisplayMode.embedded;
|
40
|
+
|
41
|
+
const findMatchingItems = (targetValue: string) => {
|
42
|
+
let filteredConversations = Object.entries(initialConversations).reduce((acc, [key, items]) => {
|
43
|
+
const filteredItems = items.filter((item) => item.text.toLowerCase().includes(targetValue.toLowerCase()));
|
44
|
+
if (filteredItems.length > 0) {
|
45
|
+
acc[key] = filteredItems;
|
46
|
+
}
|
47
|
+
return acc;
|
48
|
+
}, {});
|
49
|
+
|
50
|
+
// append message if no items are found
|
51
|
+
if (Object.keys(filteredConversations).length === 0) {
|
52
|
+
filteredConversations = [{ id: '13', noIcon: true, text: 'No results found' }];
|
53
|
+
}
|
54
|
+
return filteredConversations;
|
55
|
+
};
|
56
|
+
|
57
|
+
return (
|
58
|
+
<>
|
59
|
+
<Checkbox
|
60
|
+
label="Display drawer"
|
61
|
+
isChecked={isOpen}
|
62
|
+
onChange={() => {
|
63
|
+
setIsOpen(!isOpen);
|
64
|
+
setConversations(initialConversations);
|
65
|
+
}}
|
66
|
+
id="drawer-visible"
|
67
|
+
name="drawer-visible"
|
68
|
+
/>
|
69
|
+
<ChatbotConversationHistoryNav
|
70
|
+
displayMode={displayMode}
|
71
|
+
onDrawerToggle={() => setIsOpen(!isOpen)}
|
72
|
+
isDrawerOpen={isOpen}
|
73
|
+
setIsDrawerOpen={setIsOpen}
|
74
|
+
// eslint-disable-next-line no-console
|
75
|
+
onSelectActiveItem={(e, selectedItem) => console.log(`Selected history item with id ${selectedItem}`)}
|
76
|
+
conversations={conversations}
|
77
|
+
onNewChat={() => {
|
78
|
+
setIsOpen(!isOpen);
|
79
|
+
}}
|
80
|
+
handleTextInputChange={(value: string) => {
|
81
|
+
if (value === '') {
|
82
|
+
setConversations(initialConversations);
|
83
|
+
}
|
84
|
+
// this is where you would perform search on the items in the drawer
|
85
|
+
// and update the state
|
86
|
+
const newConversations: { [key: string]: Conversation[] } = findMatchingItems(value);
|
87
|
+
setConversations(newConversations);
|
88
|
+
}}
|
89
|
+
drawerContent={<div>Drawer content</div>}
|
90
|
+
drawerPanelContentProps={{ isResizable: true, minSize: '200px' }}
|
91
|
+
/>
|
92
|
+
</>
|
93
|
+
);
|
94
|
+
};
|
@@ -371,6 +371,16 @@ If you're showing a conversation that is already active, you can set the `active
|
|
371
371
|
|
372
372
|
```
|
373
373
|
|
374
|
+
### Resizable drawer
|
375
|
+
|
376
|
+
By default, the conversation history drawer has a fixed width (384px) and a focus trap. To provide users with more flexibility as they navigate their conversation history, or to better support embedded ChatBots on tablet-sized devices or smaller browser windows, you can instead make the drawer resizable. By default, even resizable drawers will still open to their full width on mobile devices.
|
377
|
+
|
378
|
+
In this example, the drawer can be resized up to the max size of the parent and resized down to 200px wide. To customize this behavior further (including width, style, and focus behavior) use PatternFly [`<Drawer>` props](/components/drawer#props), [`<DrawerPanelContent>` props](/components/drawer/#drawerpanelcontent), or any other drawer subcomponents.
|
379
|
+
|
380
|
+
```js file="./ChatbotHeaderDrawerResizable.tsx"
|
381
|
+
|
382
|
+
```
|
383
|
+
|
374
384
|
### Drawer with simple menu
|
375
385
|
|
376
386
|
The drawer can also be used to display a list of basic menu items.
|
@@ -21,7 +21,8 @@ propComponents:
|
|
21
21
|
'ChatbotFootnote',
|
22
22
|
'MessageBox',
|
23
23
|
'Message',
|
24
|
-
'MessageBarWithAttachMenuProps'
|
24
|
+
'MessageBarWithAttachMenuProps',
|
25
|
+
'CompareProps'
|
25
26
|
]
|
26
27
|
sortValue: 2
|
27
28
|
---
|
@@ -34,6 +35,7 @@ import ChatbotFooter, { ChatbotFootnote } from '@patternfly/chatbot/dist/dynamic
|
|
34
35
|
import MessageBar from '@patternfly/chatbot/dist/dynamic/MessageBar';
|
35
36
|
import MessageBox from '@patternfly/chatbot/dist/dynamic/MessageBox';
|
36
37
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
38
|
+
import Compare from '@patternfly/chatbot/dist/dynamic/Compare';
|
37
39
|
import ChatbotConversationHistoryNav from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
|
38
40
|
|
39
41
|
import ChatbotHeader, {
|
@@ -103,3 +105,24 @@ This demo displays an embedded ChatBot. Embedded ChatBots are meant to be placed
|
|
103
105
|
```js file="./EmbeddedChatbot.tsx" isFullscreen
|
104
106
|
|
105
107
|
```
|
108
|
+
|
109
|
+
### Comparing ChatBots
|
110
|
+
|
111
|
+
To let users compare how different ChatBots respond to the same prompt, you can add multiple ChatBots within the same window. The following demo illustrates a comparison view pattern that allows users to toggle between different conversations in a single ChatBot window.
|
112
|
+
<br /><br />
|
113
|
+
Your code structure should look like this:
|
114
|
+
|
115
|
+
```noLive
|
116
|
+
<Page ... >
|
117
|
+
<div className="pf-chatbot__compare-container">
|
118
|
+
<Compare ... />
|
119
|
+
<ChatbotFooter ... >
|
120
|
+
<MessageBar ... />
|
121
|
+
</ChatbotFooter>
|
122
|
+
</div>
|
123
|
+
</Page>
|
124
|
+
```
|
125
|
+
|
126
|
+
```js file="./EmbeddedComparisonChatbot.tsx" isFullscreen
|
127
|
+
|
128
|
+
```
|
package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedComparisonChatbot.tsx
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
import {
|
4
|
+
Page,
|
5
|
+
Masthead,
|
6
|
+
MastheadMain,
|
7
|
+
MastheadBrand,
|
8
|
+
MastheadLogo,
|
9
|
+
PageSidebarBody,
|
10
|
+
PageSidebar,
|
11
|
+
MastheadToggle,
|
12
|
+
PageToggleButton
|
13
|
+
} from '@patternfly/react-core';
|
14
|
+
import Chatbot, { ChatbotDisplayMode } from '@patternfly/chatbot/dist/dynamic/Chatbot';
|
15
|
+
import ChatbotContent from '@patternfly/chatbot/dist/dynamic/ChatbotContent';
|
16
|
+
import ChatbotWelcomePrompt from '@patternfly/chatbot/dist/dynamic/ChatbotWelcomePrompt';
|
17
|
+
import ChatbotFooter from '@patternfly/chatbot/dist/dynamic/ChatbotFooter';
|
18
|
+
import MessageBar from '@patternfly/chatbot/dist/dynamic/MessageBar';
|
19
|
+
import MessageBox from '@patternfly/chatbot/dist/dynamic/MessageBox';
|
20
|
+
import Message, { MessageProps } from '@patternfly/chatbot/dist/dynamic/Message';
|
21
|
+
import ChatbotHeader, { ChatbotHeaderMain } from '@patternfly/chatbot/dist/dynamic/ChatbotHeader';
|
22
|
+
import Compare from '@patternfly/chatbot/dist/dynamic/Compare';
|
23
|
+
import { BarsIcon } from '@patternfly/react-icons';
|
24
|
+
import userAvatar from '../Messages/user_avatar.svg';
|
25
|
+
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
26
|
+
|
27
|
+
export const CompareChild = ({ name, input, hasNewInput, setIsSendButtonDisabled }) => {
|
28
|
+
const [messages, setMessages] = React.useState<MessageProps[]>([]);
|
29
|
+
const [announcement, setAnnouncement] = React.useState<string>();
|
30
|
+
const scrollToBottomRef = React.useRef<HTMLDivElement>(null);
|
31
|
+
const displayMode = ChatbotDisplayMode.embedded;
|
32
|
+
|
33
|
+
// you will likely want to come up with your own unique id function; this is for demo purposes only
|
34
|
+
const generateId = () => {
|
35
|
+
const id = Date.now() + Math.random();
|
36
|
+
return id.toString();
|
37
|
+
};
|
38
|
+
|
39
|
+
const handleSend = (input: string) => {
|
40
|
+
const date = new Date();
|
41
|
+
const newMessages: MessageProps[] = [];
|
42
|
+
messages.forEach((message) => newMessages.push(message));
|
43
|
+
newMessages.push({
|
44
|
+
avatar: userAvatar,
|
45
|
+
avatarProps: { isBordered: true },
|
46
|
+
id: generateId(),
|
47
|
+
name: 'You',
|
48
|
+
role: 'user',
|
49
|
+
content: input,
|
50
|
+
timestamp: `${date?.toLocaleDateString()} ${date?.toLocaleTimeString()}`
|
51
|
+
});
|
52
|
+
newMessages.push({
|
53
|
+
avatar: patternflyAvatar,
|
54
|
+
id: generateId(),
|
55
|
+
name,
|
56
|
+
role: 'bot',
|
57
|
+
timestamp: `${date?.toLocaleDateString()} ${date?.toLocaleTimeString()}`,
|
58
|
+
isLoading: true
|
59
|
+
});
|
60
|
+
setMessages(newMessages);
|
61
|
+
// make announcement to assistive devices that new messages have been added
|
62
|
+
setAnnouncement(`Message from You: ${input}. Message from ${name} is loading.`);
|
63
|
+
|
64
|
+
// this is for demo purposes only; in a real situation, there would be an API response we would wait for
|
65
|
+
setTimeout(() => {
|
66
|
+
const loadedMessages: MessageProps[] = [];
|
67
|
+
// we can't use structuredClone since messages contains functions, but we can't mutate
|
68
|
+
// items that are going into state or the UI won't update correctly
|
69
|
+
newMessages.forEach((message) => loadedMessages.push(message));
|
70
|
+
loadedMessages.pop();
|
71
|
+
loadedMessages.push({
|
72
|
+
id: generateId(),
|
73
|
+
role: 'bot',
|
74
|
+
content: `API response from ${name} goes here`,
|
75
|
+
name,
|
76
|
+
avatar: patternflyAvatar,
|
77
|
+
isLoading: false,
|
78
|
+
actions: {
|
79
|
+
// eslint-disable-next-line no-console
|
80
|
+
positive: { onClick: () => console.log('Good response') },
|
81
|
+
// eslint-disable-next-line no-console
|
82
|
+
negative: { onClick: () => console.log('Bad response') },
|
83
|
+
// eslint-disable-next-line no-console
|
84
|
+
copy: { onClick: () => console.log('Copy') },
|
85
|
+
// eslint-disable-next-line no-console
|
86
|
+
share: { onClick: () => console.log('Share') },
|
87
|
+
// eslint-disable-next-line no-console
|
88
|
+
listen: { onClick: () => console.log('Listen') }
|
89
|
+
},
|
90
|
+
timestamp: date.toLocaleString()
|
91
|
+
});
|
92
|
+
setMessages(loadedMessages);
|
93
|
+
// make announcement to assistive devices that new message has loaded
|
94
|
+
setAnnouncement(`Message from ${name}: API response goes here`);
|
95
|
+
setIsSendButtonDisabled(false);
|
96
|
+
}, 5000);
|
97
|
+
};
|
98
|
+
|
99
|
+
React.useEffect(() => {
|
100
|
+
if (input) {
|
101
|
+
handleSend(input);
|
102
|
+
}
|
103
|
+
}, [hasNewInput]);
|
104
|
+
|
105
|
+
// Auto-scrolls to the latest message
|
106
|
+
React.useEffect(() => {
|
107
|
+
// don't scroll the first load, but scroll if there's a current stream or a new source has popped up
|
108
|
+
if (messages.length > 0) {
|
109
|
+
scrollToBottomRef.current?.scrollIntoView();
|
110
|
+
}
|
111
|
+
}, [messages]);
|
112
|
+
|
113
|
+
return (
|
114
|
+
<Chatbot displayMode={displayMode}>
|
115
|
+
<ChatbotHeader>
|
116
|
+
<ChatbotHeaderMain>{name}</ChatbotHeaderMain>
|
117
|
+
</ChatbotHeader>
|
118
|
+
<ChatbotContent>
|
119
|
+
<MessageBox ariaLabel={`Scrollable message log for ${name}`} announcement={announcement}>
|
120
|
+
<ChatbotWelcomePrompt title="Hello, Chatbot User" description="How may I help you today?" />
|
121
|
+
{messages.map((message) => (
|
122
|
+
<Message key={message.id} {...message} />
|
123
|
+
))}
|
124
|
+
<div ref={scrollToBottomRef}></div>
|
125
|
+
</MessageBox>
|
126
|
+
</ChatbotContent>
|
127
|
+
</Chatbot>
|
128
|
+
);
|
129
|
+
};
|
130
|
+
|
131
|
+
export const EmbeddedComparisonChatbotDemo: React.FunctionComponent = () => {
|
132
|
+
const [input, setInput] = React.useState<string>();
|
133
|
+
const [hasNewInput, setHasNewInput] = React.useState(false);
|
134
|
+
const [isSidebarOpen, setIsSidebarOpen] = React.useState(false);
|
135
|
+
const [isSendButtonDisabled, setIsSendButtonDisabled] = React.useState(false);
|
136
|
+
|
137
|
+
const handleSend = (value: string) => {
|
138
|
+
setInput(value);
|
139
|
+
setHasNewInput(!hasNewInput);
|
140
|
+
setIsSendButtonDisabled(true);
|
141
|
+
};
|
142
|
+
|
143
|
+
const masthead = (
|
144
|
+
<Masthead>
|
145
|
+
<MastheadMain>
|
146
|
+
<MastheadToggle>
|
147
|
+
<PageToggleButton
|
148
|
+
variant="plain"
|
149
|
+
aria-label="Global navigation"
|
150
|
+
isSidebarOpen={isSidebarOpen}
|
151
|
+
onSidebarToggle={() => setIsSidebarOpen(!isSidebarOpen)}
|
152
|
+
id="fill-nav-toggle"
|
153
|
+
>
|
154
|
+
<BarsIcon />
|
155
|
+
</PageToggleButton>
|
156
|
+
</MastheadToggle>
|
157
|
+
<MastheadBrand>
|
158
|
+
<MastheadLogo href="https://patternfly.org" target="_blank">
|
159
|
+
Logo
|
160
|
+
</MastheadLogo>
|
161
|
+
</MastheadBrand>
|
162
|
+
</MastheadMain>
|
163
|
+
</Masthead>
|
164
|
+
);
|
165
|
+
|
166
|
+
const sidebar = (
|
167
|
+
<PageSidebar isSidebarOpen={isSidebarOpen} id="fill-sidebar">
|
168
|
+
<PageSidebarBody>Navigation</PageSidebarBody>
|
169
|
+
</PageSidebar>
|
170
|
+
);
|
171
|
+
|
172
|
+
return (
|
173
|
+
<Page masthead={masthead} sidebar={sidebar} isContentFilled>
|
174
|
+
<div className="pf-chatbot__compare-container">
|
175
|
+
<Compare
|
176
|
+
firstChild={
|
177
|
+
<CompareChild
|
178
|
+
input={input}
|
179
|
+
hasNewInput={hasNewInput}
|
180
|
+
name="ChatBot 1"
|
181
|
+
setIsSendButtonDisabled={setIsSendButtonDisabled}
|
182
|
+
/>
|
183
|
+
}
|
184
|
+
secondChild={
|
185
|
+
<CompareChild
|
186
|
+
input={input}
|
187
|
+
hasNewInput={hasNewInput}
|
188
|
+
name="ChatBot 2"
|
189
|
+
setIsSendButtonDisabled={setIsSendButtonDisabled}
|
190
|
+
/>
|
191
|
+
}
|
192
|
+
firstChildDisplayName="ChatBot 1"
|
193
|
+
secondChildDisplayName="ChatBot 2"
|
194
|
+
/>
|
195
|
+
<ChatbotFooter>
|
196
|
+
<MessageBar
|
197
|
+
onSendMessage={handleSend}
|
198
|
+
hasAttachButton={false}
|
199
|
+
alwayShowSendButton
|
200
|
+
isSendButtonDisabled={isSendButtonDisabled}
|
201
|
+
/>
|
202
|
+
</ChatbotFooter>
|
203
|
+
</div>
|
204
|
+
</Page>
|
205
|
+
);
|
206
|
+
};
|
@@ -123,4 +123,113 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
123
123
|
expect(screen.queryByText('ChatBot documentation')).not.toBeInTheDocument();
|
124
124
|
});
|
125
125
|
});
|
126
|
+
|
127
|
+
it('should be resizable', () => {
|
128
|
+
render(
|
129
|
+
<ChatbotConversationHistoryNav
|
130
|
+
onDrawerToggle={onDrawerToggle}
|
131
|
+
isDrawerOpen={true}
|
132
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
133
|
+
setIsDrawerOpen={jest.fn()}
|
134
|
+
conversations={initialConversations}
|
135
|
+
drawerPanelContentProps={{ isResizable: true, minSize: '200px' }}
|
136
|
+
/>
|
137
|
+
);
|
138
|
+
expect(screen.getByRole('dialog', { name: /Resize/i })).toBeTruthy();
|
139
|
+
expect(screen.getByRole('separator', { name: /Resize/i })).toBeTruthy();
|
140
|
+
expect(screen.getByRole('dialog', { name: /Resize/i })).toHaveAttribute(
|
141
|
+
'style',
|
142
|
+
'--pf-v6-c-drawer__panel--md--FlexBasis: 384px; --pf-v6-c-drawer__panel--md--FlexBasis--min: 200px;'
|
143
|
+
);
|
144
|
+
});
|
145
|
+
|
146
|
+
it('should accept drawerContentProps', () => {
|
147
|
+
const { container } = render(
|
148
|
+
<ChatbotConversationHistoryNav
|
149
|
+
onDrawerToggle={onDrawerToggle}
|
150
|
+
isDrawerOpen={true}
|
151
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
152
|
+
setIsDrawerOpen={jest.fn()}
|
153
|
+
conversations={initialConversations}
|
154
|
+
drawerContentProps={{ className: 'test' }}
|
155
|
+
/>
|
156
|
+
);
|
157
|
+
const element = container.querySelector('.test');
|
158
|
+
expect(element).toBeInTheDocument();
|
159
|
+
});
|
160
|
+
|
161
|
+
it('should accept drawerContentBodyProps', () => {
|
162
|
+
const { container } = render(
|
163
|
+
<ChatbotConversationHistoryNav
|
164
|
+
onDrawerToggle={onDrawerToggle}
|
165
|
+
isDrawerOpen={true}
|
166
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
167
|
+
setIsDrawerOpen={jest.fn()}
|
168
|
+
conversations={initialConversations}
|
169
|
+
drawerContentBodyProps={{ className: 'test' }}
|
170
|
+
/>
|
171
|
+
);
|
172
|
+
const element = container.querySelector('.test');
|
173
|
+
expect(element).toBeInTheDocument();
|
174
|
+
});
|
175
|
+
|
176
|
+
it('should accept drawerHeadProps', () => {
|
177
|
+
const { container } = render(
|
178
|
+
<ChatbotConversationHistoryNav
|
179
|
+
onDrawerToggle={onDrawerToggle}
|
180
|
+
isDrawerOpen={true}
|
181
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
182
|
+
setIsDrawerOpen={jest.fn()}
|
183
|
+
conversations={initialConversations}
|
184
|
+
drawerHeadProps={{ className: 'test' }}
|
185
|
+
/>
|
186
|
+
);
|
187
|
+
const element = container.querySelector('.test');
|
188
|
+
expect(element).toBeInTheDocument();
|
189
|
+
});
|
190
|
+
|
191
|
+
it('should accept drawerActionsProps', () => {
|
192
|
+
const { container } = render(
|
193
|
+
<ChatbotConversationHistoryNav
|
194
|
+
onDrawerToggle={onDrawerToggle}
|
195
|
+
isDrawerOpen={true}
|
196
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
197
|
+
setIsDrawerOpen={jest.fn()}
|
198
|
+
conversations={initialConversations}
|
199
|
+
drawerActionsProps={{ className: 'test' }}
|
200
|
+
/>
|
201
|
+
);
|
202
|
+
const element = container.querySelector('.test');
|
203
|
+
expect(element).toBeInTheDocument();
|
204
|
+
});
|
205
|
+
|
206
|
+
it('should accept drawerCloseButtonProps', () => {
|
207
|
+
const { container } = render(
|
208
|
+
<ChatbotConversationHistoryNav
|
209
|
+
onDrawerToggle={onDrawerToggle}
|
210
|
+
isDrawerOpen={true}
|
211
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
212
|
+
setIsDrawerOpen={jest.fn()}
|
213
|
+
conversations={initialConversations}
|
214
|
+
drawerCloseButtonProps={{ className: 'test' }}
|
215
|
+
/>
|
216
|
+
);
|
217
|
+
const element = container.querySelector('.test');
|
218
|
+
expect(element).toBeInTheDocument();
|
219
|
+
});
|
220
|
+
|
221
|
+
it('should accept drawerPanelBodyProps', () => {
|
222
|
+
const { container } = render(
|
223
|
+
<ChatbotConversationHistoryNav
|
224
|
+
onDrawerToggle={onDrawerToggle}
|
225
|
+
isDrawerOpen={true}
|
226
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
227
|
+
setIsDrawerOpen={jest.fn()}
|
228
|
+
conversations={initialConversations}
|
229
|
+
drawerPanelBodyProps={{ className: 'test' }}
|
230
|
+
/>
|
231
|
+
);
|
232
|
+
const element = container.querySelector('.test');
|
233
|
+
expect(element).toBeInTheDocument();
|
234
|
+
});
|
126
235
|
});
|
@@ -22,7 +22,14 @@ import {
|
|
22
22
|
MenuItem,
|
23
23
|
MenuContent,
|
24
24
|
MenuItemProps,
|
25
|
-
MenuProps
|
25
|
+
MenuProps,
|
26
|
+
DrawerPanelContentProps,
|
27
|
+
DrawerContentProps,
|
28
|
+
DrawerContentBodyProps,
|
29
|
+
DrawerHeadProps,
|
30
|
+
DrawerActionsProps,
|
31
|
+
DrawerCloseButtonProps,
|
32
|
+
DrawerPanelBodyProps
|
26
33
|
} from '@patternfly/react-core';
|
27
34
|
|
28
35
|
import { OutlinedCommentAltIcon } from '@patternfly/react-icons';
|
@@ -82,6 +89,20 @@ export interface ChatbotConversationHistoryNavProps extends DrawerProps {
|
|
82
89
|
drawerActionsTestId?: string;
|
83
90
|
/** Additional props applied to menu */
|
84
91
|
menuProps?: MenuProps;
|
92
|
+
/** Additional props applied to panel */
|
93
|
+
drawerPanelContentProps?: DrawerPanelContentProps;
|
94
|
+
/** Additional props applied to drawer content */
|
95
|
+
drawerContentProps?: Omit<DrawerContentProps, 'panelContent'>;
|
96
|
+
/** Additional props applied to drawer content body */
|
97
|
+
drawerContentBodyProps?: DrawerContentBodyProps;
|
98
|
+
/** Additional props applied to drawer head */
|
99
|
+
drawerHeadProps?: DrawerHeadProps;
|
100
|
+
/** Additional props applied to drawer actions */
|
101
|
+
drawerActionsProps?: DrawerActionsProps;
|
102
|
+
/** Additional props applied to drawer close button */
|
103
|
+
drawerCloseButtonProps?: DrawerCloseButtonProps;
|
104
|
+
/** Additional props appleid to drawer panel body */
|
105
|
+
drawerPanelBodyProps?: DrawerPanelBodyProps;
|
85
106
|
}
|
86
107
|
|
87
108
|
export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConversationHistoryNavProps> = ({
|
@@ -101,6 +122,13 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
101
122
|
reverseButtonOrder = false,
|
102
123
|
drawerActionsTestId = 'chatbot-nav-drawer-actions',
|
103
124
|
menuProps,
|
125
|
+
drawerPanelContentProps,
|
126
|
+
drawerContentProps,
|
127
|
+
drawerContentBodyProps,
|
128
|
+
drawerHeadProps,
|
129
|
+
drawerActionsProps,
|
130
|
+
drawerCloseButtonProps,
|
131
|
+
drawerPanelBodyProps,
|
104
132
|
...props
|
105
133
|
}: ChatbotConversationHistoryNavProps) => {
|
106
134
|
const drawerRef = React.useRef<HTMLDivElement>(null);
|
@@ -173,13 +201,14 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
173
201
|
);
|
174
202
|
|
175
203
|
const panelContent = (
|
176
|
-
<DrawerPanelContent focusTrap={{ enabled: true }}
|
177
|
-
<DrawerHead>
|
204
|
+
<DrawerPanelContent focusTrap={{ enabled: true }} defaultSize="384px" {...drawerPanelContentProps}>
|
205
|
+
<DrawerHead {...drawerHeadProps}>
|
178
206
|
<DrawerActions
|
179
207
|
data-testid={drawerActionsTestId}
|
180
208
|
className={reverseButtonOrder ? 'pf-v6-c-drawer__actions--reversed' : ''}
|
209
|
+
{...drawerActionsProps}
|
181
210
|
>
|
182
|
-
<DrawerCloseButton onClick={onDrawerToggle} />
|
211
|
+
<DrawerCloseButton onClick={onDrawerToggle} {...drawerCloseButtonProps} />
|
183
212
|
{onNewChat && <Button onClick={onNewChat}>{newChatButtonText}</Button>}
|
184
213
|
</DrawerActions>
|
185
214
|
</DrawerHead>
|
@@ -192,7 +221,7 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
192
221
|
/>
|
193
222
|
</div>
|
194
223
|
)}
|
195
|
-
<DrawerPanelBody>{menuContent}</DrawerPanelBody>
|
224
|
+
<DrawerPanelBody {...drawerPanelBodyProps}>{menuContent}</DrawerPanelBody>
|
196
225
|
</DrawerPanelContent>
|
197
226
|
);
|
198
227
|
|
@@ -217,8 +246,8 @@ export const ChatbotConversationHistoryNav: React.FunctionComponent<ChatbotConve
|
|
217
246
|
isInline={displayMode === ChatbotDisplayMode.fullscreen || displayMode === ChatbotDisplayMode.embedded}
|
218
247
|
{...props}
|
219
248
|
>
|
220
|
-
<DrawerContent panelContent={panelContent}>
|
221
|
-
<DrawerContentBody>
|
249
|
+
<DrawerContent panelContent={panelContent} {...drawerContentProps}>
|
250
|
+
<DrawerContentBody {...drawerContentBodyProps}>
|
222
251
|
<>
|
223
252
|
<div
|
224
253
|
className={`${isDrawerOpen && (displayMode === ChatbotDisplayMode.default || displayMode === ChatbotDisplayMode.docked) ? 'pf-v6-c-backdrop pf-chatbot__drawer-backdrop' : undefined} `}
|