@patternfly/chatbot 2.2.1 → 6.3.0-prerelease.1
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 +4 -0
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +7 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +23 -0
- package/dist/cjs/Message/Message.d.ts +17 -1
- package/dist/cjs/Message/Message.js +53 -34
- package/dist/cjs/Message/Message.test.js +52 -0
- package/dist/cjs/Message/MessageInput.d.ts +18 -0
- package/dist/cjs/Message/MessageInput.js +34 -0
- package/dist/cjs/MessageBar/MicrophoneButton.js +1 -1
- package/dist/cjs/MessageBox/MessageBox.js +5 -5
- package/dist/cjs/SourcesCard/SourcesCard.d.ts +7 -1
- package/dist/cjs/SourcesCard/SourcesCard.js +16 -10
- package/dist/cjs/SourcesCard/SourcesCard.test.js +25 -15
- package/dist/cjs/tracking/console_tracking_provider.d.ts +4 -5
- package/dist/cjs/tracking/console_tracking_provider.js +22 -15
- package/dist/cjs/tracking/posthog_tracking_provider.d.ts +2 -2
- package/dist/cjs/tracking/posthog_tracking_provider.js +21 -12
- package/dist/cjs/tracking/segment_tracking_provider.d.ts +2 -2
- package/dist/cjs/tracking/segment_tracking_provider.js +21 -12
- package/dist/cjs/tracking/trackingProviderProxy.d.ts +1 -1
- package/dist/cjs/tracking/trackingProviderProxy.js +2 -2
- package/dist/cjs/tracking/tracking_api.d.ts +1 -1
- package/dist/cjs/tracking/tracking_registry.js +46 -12
- package/dist/cjs/tracking/tracking_spi.d.ts +15 -5
- package/dist/cjs/tracking/tracking_spi.js +9 -0
- package/dist/cjs/tracking/umami_tracking_provider.d.ts +6 -2
- package/dist/cjs/tracking/umami_tracking_provider.js +66 -22
- package/dist/css/main.css +7 -7
- package/dist/css/main.css.map +1 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +4 -0
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +7 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +23 -0
- package/dist/esm/Message/Message.d.ts +17 -1
- package/dist/esm/Message/Message.js +53 -34
- package/dist/esm/Message/Message.test.js +52 -0
- package/dist/esm/Message/MessageInput.d.ts +18 -0
- package/dist/esm/Message/MessageInput.js +29 -0
- package/dist/esm/MessageBar/MicrophoneButton.js +1 -1
- package/dist/esm/MessageBox/MessageBox.js +5 -5
- package/dist/esm/SourcesCard/SourcesCard.d.ts +7 -1
- package/dist/esm/SourcesCard/SourcesCard.js +17 -11
- package/dist/esm/SourcesCard/SourcesCard.test.js +25 -15
- package/dist/esm/tracking/console_tracking_provider.d.ts +4 -5
- package/dist/esm/tracking/console_tracking_provider.js +22 -15
- package/dist/esm/tracking/posthog_tracking_provider.d.ts +2 -2
- package/dist/esm/tracking/posthog_tracking_provider.js +21 -12
- package/dist/esm/tracking/segment_tracking_provider.d.ts +2 -2
- package/dist/esm/tracking/segment_tracking_provider.js +21 -12
- package/dist/esm/tracking/trackingProviderProxy.d.ts +1 -1
- package/dist/esm/tracking/trackingProviderProxy.js +2 -2
- package/dist/esm/tracking/tracking_api.d.ts +1 -1
- package/dist/esm/tracking/tracking_registry.js +46 -12
- package/dist/esm/tracking/tracking_spi.d.ts +15 -5
- package/dist/esm/tracking/tracking_spi.js +8 -1
- package/dist/esm/tracking/umami_tracking_provider.d.ts +6 -2
- package/dist/esm/tracking/umami_tracking_provider.js +66 -22
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md +18 -14
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +74 -104
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/FileDetailsLabel.tsx +48 -37
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickResponses.tsx +10 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithSources.tsx +51 -14
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +3 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +80 -104
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +35 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx +13 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx +6 -3
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachment.tsx +2 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +2 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotInDrawer.tsx +2 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedChatbot.tsx +2 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedComparisonChatbot.tsx +62 -57
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Feedback.tsx +2 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +53 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +14 -0
- package/src/Message/Message.scss +4 -0
- package/src/Message/Message.test.tsx +62 -0
- package/src/Message/Message.tsx +111 -53
- package/src/Message/MessageInput.tsx +59 -0
- package/src/MessageBar/MicrophoneButton.tsx +1 -1
- package/src/MessageBox/MessageBox.tsx +5 -5
- package/src/SourcesCard/SourcesCard.scss +3 -7
- package/src/SourcesCard/SourcesCard.test.tsx +30 -22
- package/src/SourcesCard/SourcesCard.tsx +54 -12
- package/src/tracking/console_tracking_provider.ts +21 -17
- package/src/tracking/posthog_tracking_provider.ts +20 -13
- package/src/tracking/segment_tracking_provider.ts +20 -13
- package/src/tracking/trackingProviderProxy.ts +2 -2
- package/src/tracking/tracking_api.ts +1 -1
- package/src/tracking/tracking_registry.ts +46 -13
- package/src/tracking/tracking_spi.ts +18 -7
- package/src/tracking/umami_tracking_provider.ts +76 -20
- package/src/SourcesCard/__snapshots__/SourcesCard.test.tsx.snap +0 -34
@@ -2,38 +2,48 @@ import React from 'react';
|
|
2
2
|
|
3
3
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
4
4
|
import userAvatar from './user_avatar.svg';
|
5
|
-
import {
|
5
|
+
import {
|
6
|
+
AlertActionLink,
|
7
|
+
MenuToggle,
|
8
|
+
MenuToggleElement,
|
9
|
+
Select,
|
10
|
+
SelectList,
|
11
|
+
SelectOption
|
12
|
+
} from '@patternfly/react-core';
|
6
13
|
|
7
14
|
export const UserMessageExample: React.FunctionComponent = () => {
|
8
|
-
const [variant, setVariant] = React.useState('
|
15
|
+
const [variant, setVariant] = React.useState<string>('Code');
|
16
|
+
const [isEditable, setIsEditable] = React.useState<boolean>(true);
|
17
|
+
const [isOpen, setIsOpen] = React.useState<boolean>(false);
|
18
|
+
const [selected, setSelected] = React.useState<string>('Message content type');
|
9
19
|
|
10
20
|
/* eslint-disable indent */
|
11
21
|
const renderContent = () => {
|
12
22
|
switch (variant) {
|
13
|
-
case '
|
23
|
+
case 'Code':
|
14
24
|
return code;
|
15
|
-
case '
|
25
|
+
case 'Inline code':
|
16
26
|
return inlineCode;
|
17
|
-
case '
|
27
|
+
case 'Heading':
|
18
28
|
return heading;
|
19
|
-
case '
|
29
|
+
case 'Emphasis':
|
20
30
|
return emphasis;
|
21
|
-
case '
|
31
|
+
case 'Block quotes':
|
22
32
|
return blockQuotes;
|
23
|
-
case '
|
33
|
+
case 'Ordered list':
|
24
34
|
return orderedList;
|
25
|
-
case '
|
35
|
+
case 'Unordered list':
|
26
36
|
return unorderedList;
|
27
|
-
case '
|
37
|
+
case 'More complex list':
|
28
38
|
return moreComplexList;
|
29
|
-
case '
|
39
|
+
case 'Link':
|
30
40
|
return link;
|
31
|
-
case '
|
41
|
+
case 'Table':
|
32
42
|
return table;
|
33
|
-
case '
|
43
|
+
case 'Image':
|
34
44
|
return image;
|
35
45
|
default:
|
36
|
-
return;
|
46
|
+
return '';
|
37
47
|
}
|
38
48
|
};
|
39
49
|
/* eslint-enable indent */
|
@@ -155,6 +165,32 @@ _Italic text, formatted with single underscores_
|
|
155
165
|
)
|
156
166
|
};
|
157
167
|
|
168
|
+
const onSelect = (_event: React.MouseEvent<Element, MouseEvent> | undefined, value: string | number | undefined) => {
|
169
|
+
setVariant(value);
|
170
|
+
setSelected(value as string);
|
171
|
+
setIsOpen(false);
|
172
|
+
};
|
173
|
+
|
174
|
+
const onToggleClick = () => {
|
175
|
+
setIsOpen(!isOpen);
|
176
|
+
};
|
177
|
+
|
178
|
+
const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
|
179
|
+
<MenuToggle
|
180
|
+
className="pf-v6-u-mb-md"
|
181
|
+
ref={toggleRef}
|
182
|
+
onClick={onToggleClick}
|
183
|
+
isExpanded={isOpen}
|
184
|
+
style={
|
185
|
+
{
|
186
|
+
width: '200px'
|
187
|
+
} as React.CSSProperties
|
188
|
+
}
|
189
|
+
>
|
190
|
+
{selected}
|
191
|
+
</MenuToggle>
|
192
|
+
);
|
193
|
+
|
158
194
|
return (
|
159
195
|
<>
|
160
196
|
<Message
|
@@ -171,103 +207,43 @@ _Italic text, formatted with single underscores_
|
|
171
207
|
avatar={userAvatar}
|
172
208
|
avatarProps={{ isBordered: true }}
|
173
209
|
/>
|
174
|
-
<
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
<
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
onChange={() => setVariant('blockQuotes')}
|
200
|
-
name="user-message-type"
|
201
|
-
label="Block quote"
|
202
|
-
id="user-block-quotes"
|
203
|
-
/>
|
204
|
-
<Radio
|
205
|
-
isChecked={variant === 'emphasis'}
|
206
|
-
onChange={() => setVariant('emphasis')}
|
207
|
-
name="user-message-type"
|
208
|
-
label="Emphasis"
|
209
|
-
id="user-emphasis"
|
210
|
-
/>
|
211
|
-
<Radio
|
212
|
-
isChecked={variant === 'link'}
|
213
|
-
onChange={() => setVariant('link')}
|
214
|
-
name="user-message-type"
|
215
|
-
label="Link"
|
216
|
-
id="user-link"
|
217
|
-
/>
|
218
|
-
<Radio
|
219
|
-
isChecked={variant === 'unorderedList'}
|
220
|
-
onChange={() => setVariant('unorderedList')}
|
221
|
-
name="user-message-type"
|
222
|
-
label="Unordered list"
|
223
|
-
id="user-unordered-list"
|
224
|
-
/>
|
225
|
-
<Radio
|
226
|
-
isChecked={variant === 'orderedList'}
|
227
|
-
onChange={() => setVariant('orderedList')}
|
228
|
-
name="user-message-type"
|
229
|
-
label="Ordered list"
|
230
|
-
id="user-ordered-list"
|
231
|
-
/>
|
232
|
-
<Radio
|
233
|
-
isChecked={variant === 'moreComplexList'}
|
234
|
-
onChange={() => setVariant('moreComplexList')}
|
235
|
-
name="user-message-type"
|
236
|
-
label="More complex list"
|
237
|
-
id="user-more-complex-list"
|
238
|
-
/>
|
239
|
-
<Radio
|
240
|
-
isChecked={variant === 'table'}
|
241
|
-
onChange={() => setVariant('table')}
|
242
|
-
name="user-message-type"
|
243
|
-
label="Table"
|
244
|
-
id="user-table"
|
245
|
-
/>
|
246
|
-
<Radio
|
247
|
-
isChecked={variant === 'image'}
|
248
|
-
onChange={() => setVariant('image')}
|
249
|
-
name="user-message-type"
|
250
|
-
label="Image"
|
251
|
-
id="user-image"
|
252
|
-
/>
|
253
|
-
<Radio
|
254
|
-
isChecked={variant === 'error'}
|
255
|
-
onChange={() => setVariant('error')}
|
256
|
-
name="user-message-error"
|
257
|
-
label="Error"
|
258
|
-
id="user-error"
|
259
|
-
/>
|
260
|
-
</FormGroup>
|
261
|
-
</Form>
|
210
|
+
<Select
|
211
|
+
id="single-select"
|
212
|
+
isOpen={isOpen}
|
213
|
+
selected={selected}
|
214
|
+
onSelect={onSelect}
|
215
|
+
onOpenChange={(isOpen) => setIsOpen(isOpen)}
|
216
|
+
toggle={toggle}
|
217
|
+
shouldFocusToggleOnSelect
|
218
|
+
>
|
219
|
+
<SelectList>
|
220
|
+
<SelectOption value="Code">Code</SelectOption>
|
221
|
+
<SelectOption value="Inline code">Inline code</SelectOption>
|
222
|
+
<SelectOption value="Heading">Heading</SelectOption>
|
223
|
+
<SelectOption value="Block quotes">Block quotes</SelectOption>
|
224
|
+
<SelectOption value="Emphasis">Emphasis</SelectOption>
|
225
|
+
<SelectOption value="Link">Link</SelectOption>
|
226
|
+
<SelectOption value="Unordered list">Unordered list</SelectOption>
|
227
|
+
<SelectOption value="Ordered list">Ordered list</SelectOption>
|
228
|
+
<SelectOption value="More complex list">More complex list</SelectOption>
|
229
|
+
<SelectOption value="Table">Table</SelectOption>
|
230
|
+
<SelectOption value="Image">Image</SelectOption>
|
231
|
+
<SelectOption value="Error">Error</SelectOption>
|
232
|
+
<SelectOption value="Editable">Editable</SelectOption>
|
233
|
+
</SelectList>
|
234
|
+
</Select>
|
262
235
|
<Message
|
263
236
|
name="User"
|
264
237
|
role="user"
|
265
238
|
content={renderContent()}
|
266
239
|
avatar={userAvatar}
|
267
240
|
tableProps={
|
268
|
-
variant === '
|
241
|
+
variant === 'Table' ? { 'aria-label': 'App information and user roles for user messages' } : undefined
|
269
242
|
}
|
270
|
-
|
243
|
+
isEditable={variant === 'Editable' ? isEditable : false}
|
244
|
+
error={variant === 'Error' ? error : undefined}
|
245
|
+
onEditUpdate={() => setIsEditable(false)}
|
246
|
+
onEditCancel={() => setIsEditable(false)}
|
271
247
|
/>
|
272
248
|
</>
|
273
249
|
);
|
@@ -4,6 +4,7 @@ import ChatbotConversationHistoryNav, {
|
|
4
4
|
Conversation
|
5
5
|
} from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
|
6
6
|
import { Checkbox, EmptyStateStatus, Spinner } from '@patternfly/react-core';
|
7
|
+
import { OutlinedCommentsIcon, SearchIcon } from '@patternfly/react-icons';
|
7
8
|
|
8
9
|
const initialConversations: { [key: string]: Conversation[] } = {
|
9
10
|
Today: [{ id: '1', text: 'Red Hat products and services' }],
|
@@ -46,6 +47,18 @@ const ERROR = {
|
|
46
47
|
onClick: () => alert('Clicked Reload')
|
47
48
|
};
|
48
49
|
|
50
|
+
const NO_RESULTS = {
|
51
|
+
bodyText: 'Adjust your search query and try again. Check your spelling or try a more general term.',
|
52
|
+
titleText: 'No results found',
|
53
|
+
icon: SearchIcon
|
54
|
+
};
|
55
|
+
|
56
|
+
const EMPTY_STATE = {
|
57
|
+
bodyText: 'Access timely assistance by starting a conversation with an AI model.',
|
58
|
+
titleText: 'Start a new chat',
|
59
|
+
icon: OutlinedCommentsIcon
|
60
|
+
};
|
61
|
+
|
49
62
|
export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
50
63
|
const [isOpen, setIsOpen] = React.useState(true);
|
51
64
|
const [isButtonOrderReversed, setIsButtonOrderReversed] = React.useState(false);
|
@@ -54,10 +67,12 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
54
67
|
);
|
55
68
|
const [isLoading, setIsLoading] = React.useState(false);
|
56
69
|
const [hasError, setHasError] = React.useState(false);
|
70
|
+
const [isEmpty, setIsEmpty] = React.useState(false);
|
71
|
+
const [hasNoResults, setHasNoResults] = React.useState(false);
|
57
72
|
const displayMode = ChatbotDisplayMode.embedded;
|
58
73
|
|
59
74
|
const findMatchingItems = (targetValue: string) => {
|
60
|
-
|
75
|
+
const filteredConversations = Object.entries(initialConversations).reduce((acc, [key, items]) => {
|
61
76
|
const filteredItems = items.filter((item) => item.text.toLowerCase().includes(targetValue.toLowerCase()));
|
62
77
|
if (filteredItems.length > 0) {
|
63
78
|
acc[key] = filteredItems;
|
@@ -67,7 +82,9 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
67
82
|
|
68
83
|
// append message if no items are found
|
69
84
|
if (Object.keys(filteredConversations).length === 0) {
|
70
|
-
|
85
|
+
setHasNoResults(true);
|
86
|
+
} else {
|
87
|
+
setHasNoResults(false);
|
71
88
|
}
|
72
89
|
return filteredConversations;
|
73
90
|
};
|
@@ -105,6 +122,20 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
105
122
|
id="drawer-has-error"
|
106
123
|
name="drawer-has-error"
|
107
124
|
></Checkbox>
|
125
|
+
<Checkbox
|
126
|
+
label="Show empty state"
|
127
|
+
isChecked={isEmpty}
|
128
|
+
onChange={() => setIsEmpty(!isEmpty)}
|
129
|
+
id="drawer-is-empty"
|
130
|
+
name="drawer-is-empty"
|
131
|
+
></Checkbox>
|
132
|
+
<Checkbox
|
133
|
+
label="Show no results state"
|
134
|
+
isChecked={hasNoResults}
|
135
|
+
onChange={() => setHasNoResults(!hasNoResults)}
|
136
|
+
id="drawer-has-no-results"
|
137
|
+
name="drawer-has-no-results"
|
138
|
+
></Checkbox>
|
108
139
|
<ChatbotConversationHistoryNav
|
109
140
|
displayMode={displayMode}
|
110
141
|
onDrawerToggle={() => setIsOpen(!isOpen)}
|
@@ -129,6 +160,8 @@ export const ChatbotHeaderTitleDemo: React.FunctionComponent = () => {
|
|
129
160
|
drawerContent={<div>Drawer content</div>}
|
130
161
|
isLoading={isLoading}
|
131
162
|
errorState={hasError ? ERROR : undefined}
|
163
|
+
emptyState={isEmpty ? EMPTY_STATE : undefined}
|
164
|
+
noResultsState={hasNoResults ? NO_RESULTS : undefined}
|
132
165
|
/>
|
133
166
|
</>
|
134
167
|
);
|
package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx
CHANGED
@@ -4,6 +4,7 @@ import ChatbotConversationHistoryNav, {
|
|
4
4
|
Conversation
|
5
5
|
} from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
|
6
6
|
import { Checkbox } from '@patternfly/react-core';
|
7
|
+
import { SearchIcon } from '@patternfly/react-icons';
|
7
8
|
|
8
9
|
const initialConversations: { [key: string]: Conversation[] } = {
|
9
10
|
Today: [{ id: '1', text: 'Red Hat products and services' }],
|
@@ -31,15 +32,22 @@ const initialConversations: { [key: string]: Conversation[] } = {
|
|
31
32
|
]
|
32
33
|
};
|
33
34
|
|
35
|
+
const NO_RESULTS = {
|
36
|
+
bodyText: 'Adjust your search query and try again. Check your spelling or try a more general term.',
|
37
|
+
titleText: 'No results found',
|
38
|
+
icon: SearchIcon
|
39
|
+
};
|
40
|
+
|
34
41
|
export const ChatbotHeaderDrawerResizableDemo: React.FunctionComponent = () => {
|
35
42
|
const [isOpen, setIsOpen] = React.useState(true);
|
36
43
|
const [conversations, setConversations] = React.useState<Conversation[] | { [key: string]: Conversation[] }>(
|
37
44
|
initialConversations
|
38
45
|
);
|
46
|
+
const [showNoResults, setShowNoResults] = React.useState(false);
|
39
47
|
const displayMode = ChatbotDisplayMode.embedded;
|
40
48
|
|
41
49
|
const findMatchingItems = (targetValue: string) => {
|
42
|
-
|
50
|
+
const filteredConversations = Object.entries(initialConversations).reduce((acc, [key, items]) => {
|
43
51
|
const filteredItems = items.filter((item) => item.text.toLowerCase().includes(targetValue.toLowerCase()));
|
44
52
|
if (filteredItems.length > 0) {
|
45
53
|
acc[key] = filteredItems;
|
@@ -49,7 +57,9 @@ export const ChatbotHeaderDrawerResizableDemo: React.FunctionComponent = () => {
|
|
49
57
|
|
50
58
|
// append message if no items are found
|
51
59
|
if (Object.keys(filteredConversations).length === 0) {
|
52
|
-
|
60
|
+
setShowNoResults(true);
|
61
|
+
} else {
|
62
|
+
setShowNoResults(false);
|
53
63
|
}
|
54
64
|
return filteredConversations;
|
55
65
|
};
|
@@ -88,6 +98,7 @@ export const ChatbotHeaderDrawerResizableDemo: React.FunctionComponent = () => {
|
|
88
98
|
}}
|
89
99
|
drawerContent={<div>Drawer content</div>}
|
90
100
|
drawerPanelContentProps={{ isResizable: true, minSize: '200px' }}
|
101
|
+
emptyState={showNoResults ? NO_RESULTS : undefined}
|
91
102
|
/>
|
92
103
|
</>
|
93
104
|
);
|
@@ -83,7 +83,7 @@ import PFHorizontalLogoReverse from './PF-HorizontalLogo-Reverse.svg';
|
|
83
83
|
import userAvatar from '../Messages/user_avatar.svg';
|
84
84
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
85
85
|
import termsAndConditionsHeader from './PF-TermsAndConditionsHeader.svg';
|
86
|
-
import { CloseIcon } from '@patternfly/react-icons';
|
86
|
+
import { CloseIcon, SearchIcon, OutlinedCommentsIcon } from '@patternfly/react-icons';
|
87
87
|
|
88
88
|
## Structure
|
89
89
|
|
@@ -34,6 +34,8 @@ import userAvatar from '../Messages/user_avatar.svg';
|
|
34
34
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
35
35
|
import { getTrackingProviders } from '@patternfly/chatbot/dist/dynamic/tracking';
|
36
36
|
import { InitProps } from '@patternfly/chatbot/dist/dynamic/tracking';
|
37
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
38
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
37
39
|
|
38
40
|
const footnoteProps = {
|
39
41
|
label: 'ChatBot uses AI. Check for mistakes.',
|
@@ -98,17 +100,18 @@ export default MessageLoading;
|
|
98
100
|
const date = new Date();
|
99
101
|
|
100
102
|
const initProps: InitProps = {
|
103
|
+
verbose: false,
|
101
104
|
segmentKey: 'TODO-key', // TODO add your key here
|
102
105
|
posthogKey: 'TODO-key',
|
103
106
|
umamiKey: 'TODO-key',
|
104
|
-
umamiHostUrl: 'http://localhost:3000', // TODO where is your
|
107
|
+
umamiHostUrl: 'http://localhost:3000', // TODO where is your Umami installation?
|
105
108
|
console: true,
|
106
109
|
something: 'test'
|
107
110
|
};
|
108
111
|
|
109
112
|
const tracking = getTrackingProviders(initProps);
|
110
|
-
tracking.identify('user-123'); // TODO get real user id
|
111
|
-
tracking.trackPageView(window.
|
113
|
+
tracking.identify('user-123', { superUser: true }); // TODO get real user id + properties
|
114
|
+
tracking.trackPageView(window.location.href);
|
112
115
|
|
113
116
|
const actionEventName = 'MessageAction';
|
114
117
|
const initialMessages: MessageProps[] = [
|
@@ -29,6 +29,8 @@ import PFIconLogoColor from '../UI/PF-IconLogo-Color.svg';
|
|
29
29
|
import PFIconLogoReverse from '../UI/PF-IconLogo-Reverse.svg';
|
30
30
|
import userAvatar from '../Messages/user_avatar.svg';
|
31
31
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
32
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
33
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
32
34
|
|
33
35
|
interface ModalData {
|
34
36
|
code: string;
|
@@ -16,6 +16,8 @@ import { BellIcon, CalendarAltIcon, ClipboardIcon, CodeIcon, UploadIcon } from '
|
|
16
16
|
import { useDropzone } from 'react-dropzone';
|
17
17
|
import userAvatar from '../Messages/user_avatar.svg';
|
18
18
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
19
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
20
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
19
21
|
|
20
22
|
const initialMenuItems = [
|
21
23
|
<DropdownList key="list-1">
|
@@ -42,6 +42,8 @@ import PFIconLogoReverse from '../UI/PF-IconLogo-Reverse.svg';
|
|
42
42
|
import { BarsIcon } from '@patternfly/react-icons';
|
43
43
|
import userAvatar from '../Messages/user_avatar.svg';
|
44
44
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
45
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
46
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
45
47
|
|
46
48
|
const footnoteProps = {
|
47
49
|
label: 'ChatBot uses AI. Check for mistakes.',
|
@@ -40,6 +40,8 @@ import PFHorizontalLogoReverse from '../UI/PF-HorizontalLogo-Reverse.svg';
|
|
40
40
|
import { BarsIcon } from '@patternfly/react-icons';
|
41
41
|
import userAvatar from '../Messages/user_avatar.svg';
|
42
42
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
43
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
44
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
43
45
|
|
44
46
|
const footnoteProps = {
|
45
47
|
label: 'ChatBot uses AI. Check for mistakes.',
|
package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedComparisonChatbot.tsx
CHANGED
@@ -23,6 +23,8 @@ import Compare from '@patternfly/chatbot/dist/dynamic/Compare';
|
|
23
23
|
import { BarsIcon } from '@patternfly/react-icons';
|
24
24
|
import userAvatar from '../Messages/user_avatar.svg';
|
25
25
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
26
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
27
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
26
28
|
|
27
29
|
export const CompareChild = ({ name, input, hasNewInput, setIsSendButtonDisabled }) => {
|
28
30
|
const [messages, setMessages] = React.useState<MessageProps[]>([]);
|
@@ -36,71 +38,74 @@ export const CompareChild = ({ name, input, hasNewInput, setIsSendButtonDisabled
|
|
36
38
|
return id.toString();
|
37
39
|
};
|
38
40
|
|
39
|
-
const handleSend = (
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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({
|
41
|
+
const handleSend = React.useCallback(
|
42
|
+
(input: string) => {
|
43
|
+
const date = new Date();
|
44
|
+
const newMessages: MessageProps[] = [];
|
45
|
+
messages.forEach((message) => newMessages.push(message));
|
46
|
+
newMessages.push({
|
47
|
+
avatar: userAvatar,
|
48
|
+
avatarProps: { isBordered: true },
|
72
49
|
id: generateId(),
|
73
|
-
|
74
|
-
|
75
|
-
|
50
|
+
name: 'You',
|
51
|
+
role: 'user',
|
52
|
+
content: input,
|
53
|
+
timestamp: `${date?.toLocaleDateString()} ${date?.toLocaleTimeString()}`
|
54
|
+
});
|
55
|
+
newMessages.push({
|
76
56
|
avatar: patternflyAvatar,
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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()
|
57
|
+
id: generateId(),
|
58
|
+
name,
|
59
|
+
role: 'bot',
|
60
|
+
timestamp: `${date?.toLocaleDateString()} ${date?.toLocaleTimeString()}`,
|
61
|
+
isLoading: true
|
91
62
|
});
|
92
|
-
setMessages(
|
93
|
-
// make announcement to assistive devices that new
|
94
|
-
setAnnouncement(`Message from ${
|
95
|
-
|
96
|
-
|
97
|
-
|
63
|
+
setMessages(newMessages);
|
64
|
+
// make announcement to assistive devices that new messages have been added
|
65
|
+
setAnnouncement(`Message from You: ${input}. Message from ${name} is loading.`);
|
66
|
+
|
67
|
+
// this is for demo purposes only; in a real situation, there would be an API response we would wait for
|
68
|
+
setTimeout(() => {
|
69
|
+
const loadedMessages: MessageProps[] = [];
|
70
|
+
// we can't use structuredClone since messages contains functions, but we can't mutate
|
71
|
+
// items that are going into state or the UI won't update correctly
|
72
|
+
newMessages.forEach((message) => loadedMessages.push(message));
|
73
|
+
loadedMessages.pop();
|
74
|
+
loadedMessages.push({
|
75
|
+
id: generateId(),
|
76
|
+
role: 'bot',
|
77
|
+
content: `API response from ${name} goes here`,
|
78
|
+
name,
|
79
|
+
avatar: patternflyAvatar,
|
80
|
+
isLoading: false,
|
81
|
+
actions: {
|
82
|
+
// eslint-disable-next-line no-console
|
83
|
+
positive: { onClick: () => console.log('Good response') },
|
84
|
+
// eslint-disable-next-line no-console
|
85
|
+
negative: { onClick: () => console.log('Bad response') },
|
86
|
+
// eslint-disable-next-line no-console
|
87
|
+
copy: { onClick: () => console.log('Copy') },
|
88
|
+
// eslint-disable-next-line no-console
|
89
|
+
share: { onClick: () => console.log('Share') },
|
90
|
+
// eslint-disable-next-line no-console
|
91
|
+
listen: { onClick: () => console.log('Listen') }
|
92
|
+
},
|
93
|
+
timestamp: date.toLocaleString()
|
94
|
+
});
|
95
|
+
setMessages(loadedMessages);
|
96
|
+
// make announcement to assistive devices that new message has loaded
|
97
|
+
setAnnouncement(`Message from ${name}: API response goes here`);
|
98
|
+
setIsSendButtonDisabled(false);
|
99
|
+
}, 5000);
|
100
|
+
},
|
101
|
+
[messages, name, setIsSendButtonDisabled]
|
102
|
+
);
|
98
103
|
|
99
104
|
React.useEffect(() => {
|
100
105
|
if (input) {
|
101
106
|
handleSend(input);
|
102
107
|
}
|
103
|
-
}, [hasNewInput]);
|
108
|
+
}, [hasNewInput, input]);
|
104
109
|
|
105
110
|
// Auto-scrolls to the latest message
|
106
111
|
React.useEffect(() => {
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
3
3
|
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
4
|
+
import '@patternfly/react-core/dist/styles/base.css';
|
5
|
+
import '@patternfly/chatbot/dist/css/main.css';
|
4
6
|
|
5
7
|
export const MessageWithFeedbackExample: React.FunctionComponent = () => {
|
6
8
|
const [showUserFeedbackForm, setShowUserFeedbackForm] = React.useState(false);
|
@@ -5,6 +5,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
5
5
|
import { ChatbotDisplayMode } from '../Chatbot/Chatbot';
|
6
6
|
import ChatbotConversationHistoryNav, { Conversation } from './ChatbotConversationHistoryNav';
|
7
7
|
import { EmptyStateStatus, Spinner } from '@patternfly/react-core';
|
8
|
+
import { OutlinedCommentsIcon, SearchIcon } from '@patternfly/react-icons';
|
8
9
|
|
9
10
|
const ERROR = {
|
10
11
|
bodyText: (
|
@@ -21,6 +22,18 @@ const ERROR = {
|
|
21
22
|
onClick: () => alert('Clicked Reload')
|
22
23
|
};
|
23
24
|
|
25
|
+
const NO_RESULTS = {
|
26
|
+
bodyText: 'Adjust your search query and try again. Check your spelling or try a more general term.',
|
27
|
+
titleText: 'No results found',
|
28
|
+
icon: SearchIcon
|
29
|
+
};
|
30
|
+
|
31
|
+
const EMPTY_STATE = {
|
32
|
+
bodyText: 'Access timely assistance by starting a conversation with an AI model.',
|
33
|
+
titleText: 'Start a new chat',
|
34
|
+
icon: OutlinedCommentsIcon
|
35
|
+
};
|
36
|
+
|
24
37
|
const ERROR_WITHOUT_BUTTON = {
|
25
38
|
bodyText: (
|
26
39
|
<>
|
@@ -362,4 +375,44 @@ describe('ChatbotConversationHistoryNav', () => {
|
|
362
375
|
);
|
363
376
|
expect(screen.getByRole('dialog', { name: /Loading/i })).toBeTruthy();
|
364
377
|
});
|
378
|
+
|
379
|
+
it('should accept emptyState', () => {
|
380
|
+
render(
|
381
|
+
<ChatbotConversationHistoryNav
|
382
|
+
onDrawerToggle={onDrawerToggle}
|
383
|
+
isDrawerOpen={true}
|
384
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
385
|
+
setIsDrawerOpen={jest.fn()}
|
386
|
+
reverseButtonOrder={false}
|
387
|
+
handleTextInputChange={jest.fn()}
|
388
|
+
conversations={initialConversations}
|
389
|
+
emptyState={EMPTY_STATE}
|
390
|
+
/>
|
391
|
+
);
|
392
|
+
expect(
|
393
|
+
screen.getByRole('dialog', {
|
394
|
+
name: /Start a new chat Access timely assistance by starting a conversation with an AI model./i
|
395
|
+
})
|
396
|
+
).toBeTruthy();
|
397
|
+
});
|
398
|
+
|
399
|
+
it('should accept no results state', () => {
|
400
|
+
render(
|
401
|
+
<ChatbotConversationHistoryNav
|
402
|
+
onDrawerToggle={onDrawerToggle}
|
403
|
+
isDrawerOpen={true}
|
404
|
+
displayMode={ChatbotDisplayMode.fullscreen}
|
405
|
+
setIsDrawerOpen={jest.fn()}
|
406
|
+
reverseButtonOrder={false}
|
407
|
+
handleTextInputChange={jest.fn()}
|
408
|
+
conversations={initialConversations}
|
409
|
+
noResultsState={NO_RESULTS}
|
410
|
+
/>
|
411
|
+
);
|
412
|
+
expect(
|
413
|
+
screen.getByRole('dialog', {
|
414
|
+
name: /No results found Adjust your search query and try again. Check your spelling or try a more general term./i
|
415
|
+
})
|
416
|
+
).toBeTruthy();
|
417
|
+
});
|
365
418
|
});
|