@patternfly/chatbot 6.6.0-prerelease.1 → 6.6.0-prerelease.2

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.
@@ -1,4 +1,4 @@
1
- import { CardBodyProps, CardProps, ExpandableSectionProps } from '@patternfly/react-core';
1
+ import { CardBodyProps, CardProps, ExpandableSectionProps, SpinnerProps } from '@patternfly/react-core';
2
2
  import { type FunctionComponent } from 'react';
3
3
  import type { MarkdownContentProps } from '../MarkdownContent';
4
4
  export interface DeepThinkingProps {
@@ -26,6 +26,10 @@ export interface DeepThinkingProps {
26
26
  markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
27
27
  /** Whether to retain styles in the MarkdownContent component. Defaults to false. */
28
28
  shouldRetainStyles?: boolean;
29
+ /** Flag indicating whether the deep thinking is loading or not. */
30
+ isLoading?: boolean;
31
+ /** Additional props for the spinner component when isLoading is true. */
32
+ spinnerProps?: SpinnerProps;
29
33
  }
30
34
  export declare const DeepThinking: FunctionComponent<DeepThinkingProps>;
31
35
  export default DeepThinking;
@@ -11,7 +11,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
11
11
  const react_core_1 = require("@patternfly/react-core");
12
12
  const react_1 = require("react");
13
13
  const MarkdownContent_1 = __importDefault(require("../MarkdownContent"));
14
- const DeepThinking = ({ body, cardProps, expandableSectionProps, subheading, toggleContent, isDefaultExpanded = true, cardBodyProps, isToggleContentMarkdown, isSubheadingMarkdown, isBodyMarkdown, markdownContentProps, shouldRetainStyles = false }) => {
14
+ const DeepThinking = ({ body, cardProps, expandableSectionProps, subheading, toggleContent, isDefaultExpanded = true, cardBodyProps, isToggleContentMarkdown, isSubheadingMarkdown, isBodyMarkdown, markdownContentProps, shouldRetainStyles = false, isLoading = false, spinnerProps }) => {
15
15
  const [isExpanded, setIsExpanded] = (0, react_1.useState)(isDefaultExpanded);
16
16
  const onToggle = (_event, isExpanded) => {
17
17
  setIsExpanded(isExpanded);
@@ -20,7 +20,7 @@ const DeepThinking = ({ body, cardProps, expandableSectionProps, subheading, tog
20
20
  if (isToggleContentMarkdown && typeof toggleContent === 'string') {
21
21
  return ((0, jsx_runtime_1.jsx)(MarkdownContent_1.default, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: toggleContent }, markdownContentProps)));
22
22
  }
23
- return toggleContent;
23
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isLoading && (0, jsx_runtime_1.jsx)(react_core_1.Spinner, Object.assign({ diameter: "1em", isInline: true, style: { marginInlineEnd: '8px' } }, spinnerProps)), toggleContent] }));
24
24
  };
25
25
  const renderSubheading = () => {
26
26
  if (!subheading) {
@@ -125,4 +125,22 @@ describe('DeepThinking', () => {
125
125
  const { container } = (0, react_1.render)((0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, defaultProps, { body: body, isBodyMarkdown: true, markdownContentProps: { isPrimary: true } })));
126
126
  expect(container.querySelector('.pf-m-primary')).toBeTruthy();
127
127
  });
128
+ it('should render spinner when isLoading is true', () => {
129
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, defaultProps, { isLoading: true })));
130
+ expect(react_1.screen.getByLabelText('Contents')).toBeInTheDocument();
131
+ });
132
+ it('should not render spinner when isLoading is false', () => {
133
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, defaultProps)));
134
+ expect(react_1.screen.queryByLabelText('Contents')).not.toBeInTheDocument();
135
+ });
136
+ it('should pass spinnerProps to Spinner component', () => {
137
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(DeepThinking_1.default, Object.assign({}, defaultProps, { isLoading: true, spinnerProps: { 'aria-label': 'Custom label' } })));
138
+ expect(react_1.screen.getByLabelText('Custom label')).toBeInTheDocument();
139
+ });
140
+ it('should not render spinner when isToggleContentMarkdown is true', () => {
141
+ const toggleContent = '**Bold thinking**';
142
+ (0, react_1.render)((0, jsx_runtime_1.jsx)(DeepThinking_1.default, { toggleContent: toggleContent, isToggleContentMarkdown: true, isLoading: true }));
143
+ expect(react_1.screen.queryByLabelText('Contents')).not.toBeInTheDocument();
144
+ expect(react_1.screen.getByText('Bold thinking')).toBeInTheDocument();
145
+ });
128
146
  });
@@ -1,4 +1,4 @@
1
- import { CardBodyProps, CardProps, ExpandableSectionProps } from '@patternfly/react-core';
1
+ import { CardBodyProps, CardProps, ExpandableSectionProps, SpinnerProps } from '@patternfly/react-core';
2
2
  import { type FunctionComponent } from 'react';
3
3
  import type { MarkdownContentProps } from '../MarkdownContent';
4
4
  export interface DeepThinkingProps {
@@ -26,6 +26,10 @@ export interface DeepThinkingProps {
26
26
  markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
27
27
  /** Whether to retain styles in the MarkdownContent component. Defaults to false. */
28
28
  shouldRetainStyles?: boolean;
29
+ /** Flag indicating whether the deep thinking is loading or not. */
30
+ isLoading?: boolean;
31
+ /** Additional props for the spinner component when isLoading is true. */
32
+ spinnerProps?: SpinnerProps;
29
33
  }
30
34
  export declare const DeepThinking: FunctionComponent<DeepThinkingProps>;
31
35
  export default DeepThinking;
@@ -1,11 +1,11 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // ============================================================================
3
3
  // Deep Thinking
4
4
  // ============================================================================
5
- import { Card, CardBody, ExpandableSection } from '@patternfly/react-core';
5
+ import { Card, CardBody, ExpandableSection, Spinner } from '@patternfly/react-core';
6
6
  import { useState } from 'react';
7
7
  import MarkdownContent from '../MarkdownContent';
8
- export const DeepThinking = ({ body, cardProps, expandableSectionProps, subheading, toggleContent, isDefaultExpanded = true, cardBodyProps, isToggleContentMarkdown, isSubheadingMarkdown, isBodyMarkdown, markdownContentProps, shouldRetainStyles = false }) => {
8
+ export const DeepThinking = ({ body, cardProps, expandableSectionProps, subheading, toggleContent, isDefaultExpanded = true, cardBodyProps, isToggleContentMarkdown, isSubheadingMarkdown, isBodyMarkdown, markdownContentProps, shouldRetainStyles = false, isLoading = false, spinnerProps }) => {
9
9
  const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
10
10
  const onToggle = (_event, isExpanded) => {
11
11
  setIsExpanded(isExpanded);
@@ -14,7 +14,7 @@ export const DeepThinking = ({ body, cardProps, expandableSectionProps, subheadi
14
14
  if (isToggleContentMarkdown && typeof toggleContent === 'string') {
15
15
  return (_jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: toggleContent }, markdownContentProps)));
16
16
  }
17
- return toggleContent;
17
+ return (_jsxs(_Fragment, { children: [isLoading && _jsx(Spinner, Object.assign({ diameter: "1em", isInline: true, style: { marginInlineEnd: '8px' } }, spinnerProps)), toggleContent] }));
18
18
  };
19
19
  const renderSubheading = () => {
20
20
  if (!subheading) {
@@ -120,4 +120,22 @@ describe('DeepThinking', () => {
120
120
  const { container } = render(_jsx(DeepThinking, Object.assign({}, defaultProps, { body: body, isBodyMarkdown: true, markdownContentProps: { isPrimary: true } })));
121
121
  expect(container.querySelector('.pf-m-primary')).toBeTruthy();
122
122
  });
123
+ it('should render spinner when isLoading is true', () => {
124
+ render(_jsx(DeepThinking, Object.assign({}, defaultProps, { isLoading: true })));
125
+ expect(screen.getByLabelText('Contents')).toBeInTheDocument();
126
+ });
127
+ it('should not render spinner when isLoading is false', () => {
128
+ render(_jsx(DeepThinking, Object.assign({}, defaultProps)));
129
+ expect(screen.queryByLabelText('Contents')).not.toBeInTheDocument();
130
+ });
131
+ it('should pass spinnerProps to Spinner component', () => {
132
+ render(_jsx(DeepThinking, Object.assign({}, defaultProps, { isLoading: true, spinnerProps: { 'aria-label': 'Custom label' } })));
133
+ expect(screen.getByLabelText('Custom label')).toBeInTheDocument();
134
+ });
135
+ it('should not render spinner when isToggleContentMarkdown is true', () => {
136
+ const toggleContent = '**Bold thinking**';
137
+ render(_jsx(DeepThinking, { toggleContent: toggleContent, isToggleContentMarkdown: true, isLoading: true }));
138
+ expect(screen.queryByLabelText('Contents')).not.toBeInTheDocument();
139
+ expect(screen.getByText('Bold thinking')).toBeInTheDocument();
140
+ });
123
141
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.6.0-prerelease.1",
3
+ "version": "6.6.0-prerelease.2",
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",
@@ -16,7 +16,7 @@ import "./images.css"
16
16
 
17
17
  1. **Container:** The window that contains the entire ChatBot experience and all of its components.
18
18
  1. **Header:** A persistent region at the top of the ChatBot window that contains navigation, branding, and actions.
19
- 1. **History menu:** A menu that contains a conversation history of previous chats.
19
+ 1. **Chat history menu:** A menu that contains a history of previous chats.
20
20
  1. **Options menu:** A menu that contains settings that are relevant to your product. This typically includes display options (more details in the [ChatBot variations section](#variations)) and other general settings (more details in the [ChatBot settings and preferences section](#chatbot-settings-and-preferences)).
21
21
  1. **Messages:** Elements of the conversation between a ChatBot and user. More details can be found in the [message guidelines](#messages).
22
22
  1. **Attachments:** Details about files that a user has uploaded to the ChatBot.
@@ -43,7 +43,7 @@ import "./images.css"
43
43
 
44
44
  At the start of a new chat, you should welcome your users to the ChatBot with a greeting.
45
45
 
46
- If you have user details from their account information, you can personalize this greeting with their username or name. If you don't have this information, or if you'd prefer to not use their personal details, you should instead introduce the ChatBot:
46
+ As much as possible, the suggested prompts should consider the user’s location in the service or application, or the situation their project is undergoing. If you have user details from their account information, you can personalize this greeting with their username or name. If you don't have this information, or if you'd prefer to not use their personal details, you should instead introduce the ChatBot:
47
47
 
48
48
  <div class="ws-docs-content-img">
49
49
  ![Welcome messages.](./img/welcome-message.svg)
@@ -55,16 +55,44 @@ To help users get started quickly, it can also be helpful to include welcome pro
55
55
  ![Welcome message with prompts.](./img/welcome-elements.svg)
56
56
  </div>
57
57
 
58
- #### Source tiles
58
+ #### Source cards
59
59
 
60
- A ChatBot can share relevant sources with users, like documentation that could provide the information a user is searching for. These sources will be contained in a single tile, which users can paginate through and select to navigate to other resources.
60
+ To share relevant resources with users, like documentation containing the answer to a user's question, you can use source cards.
61
61
 
62
- To provide users with enough context, sources should have descriptive titles and descriptions. The title is limited to 1 line and the body is limited to 2 lines.
62
+ <div class="ws-docs-content-img">
63
+ ![A white card below a message from a ChatBot. In the card is blue text for the title and black text for a short description. There are four pink annotation markers pointing to major sections of the image.](./img/source-card.svg)
64
+ </div>
65
+
66
+ 1. **Source count:** Notes the number of sources shared in a card.
67
+ 2. **Source card title:** Offers a concise, descriptive title of the source content to provide users with quick context about a source. Titles are limited to 1 line and should be truncated when the text overflows or wraps.
68
+ 3. **Source card description:** Offers a concise preview or summary of the source content. We recommend limiting the length to 2 lines to provide context without overcrowding the chat window.
69
+ 4. **Pagination:** Used to navigate through all options when there are multiple source cards provided. Not displayed when only 1 source is provided.
70
+
71
+ Instead of a short preview of the linked source's content, you can choose to summarize the contents and use that summary as your description. This is helpful for in-depth resources where the context is not clear from the beginning snippet. You can also choose to elevate a quote from the resource that is most relevant to the user's question.
63
72
 
64
73
  <div class="ws-docs-content-img">
65
- ![Bot message that include multiple source tiles.](./img/source-tile.svg)
74
+ ![A single source card is show below a chatbot message.](./img/source-card-summary.svg)
66
75
  </div>
67
76
 
77
+ While we generally recommend staying within 2 lines for your source description, you can choose to provide a "show more" button that allows users to expand and view a longer description. When using expandable descriptions, it is recommended to end the description at the end of the sentence. Use your best UX judgment here&mdash;extremely lengthy descriptions can quickly fill out the chat window and obstruct previous conversation details.
78
+
79
+ <div class="ws-docs-content-img">
80
+ ![A before and after image is shown. The before image shows a single source card below a chatbot message, with a blue link at the bottom that says "show more." In the after image, additional description lines are shown and the link now says "show less."](./img/source-card-expanded.svg)
81
+ </div>
82
+
83
+ ##### Custom source cards
84
+
85
+ You can create a custom source card by utilizing additional components that make sense for your use case. The source card's flexibility can be used in a number of ways, but the following example demonstrates how you might customize its appearance to provide additional details about a source.
86
+
87
+ <div class="ws-docs-content-img">
88
+ ![A source card, annotated with four pink markers. Each marker points to a unique point of the card: a light gray subtitle below the main card title, a filled, green label beneath the card body that is labeled with a confidence % score, a blue help link is to the right of the green label that says "learn about this score", and light gray text at the bottom of the card with the last updated date.](./img/custom-source-card.svg)
89
+ </div>
90
+
91
+ 1. **Subtitle:** Additional context about the resource, such as where the documentation is hosted.
92
+ 2. **Label:** A confidence score, to indicate the likelihood that a source contains relevant information for the user.
93
+ 3. **Link with popover:** Additional context about the confidence score label.
94
+ 4. **Date:** The last time the linked resource was updated.
95
+
68
96
  #### Quick start tiles
69
97
 
70
98
  A ChatBot can share a link to a [quick start](/extensions/quick-starts) that will help users complete a given task. Users can either select **Start** or the tile's title to initiate the linked quick start.
@@ -119,7 +147,7 @@ When users select either of these icons, you should present them with either:
119
147
  1. **Close button (optional):** Closes the feedback form. The original feedback response should still be collected.
120
148
  1. **Quick responses:** Options for users to provide more context around their rating. Customize these to make the most sense for your product. You can present positive and negative options based on the response type originally selected.
121
149
  1. **Text area (optional):** Allows users to provide additional written detail if they'd like.
122
- 1. **Submit button:** Submits the feedback form and triggers the thank-you card.
150
+ 1. **Submit button:** Submits the feedback form and triggers the thank-you card.
123
151
 
124
152
  ### Message bar
125
153
 
@@ -205,7 +233,7 @@ To help users further identify the toggle, add a "Launch ChatBot" tooltip. You c
205
233
  ![Tooltips for ChatBot toggle.](./img/toggle-tooltips.svg)
206
234
  </div>
207
235
 
208
- Whichever method you choose, it is critical to be consistent with the toggle location and refer to the following the additional guidelines for each.
236
+ Whichever method you choose, it is critical to be consistent with the toggle location and refer to the following additional guidelines for each.
209
237
 
210
238
  #### Floating toggle
211
239
  When users click the toggle, the ChatBot window opens and the toggle will change to display an "angle down" icon to indicate that clicking the toggle again will minimize the ChatBot. Users can select the toggle at any point in their journey to open and close the ChatBot as needed.
@@ -250,17 +278,27 @@ If a UI element within the page content is an AI/ChatBot-supported feature, the
250
278
  ![Menu item for an AI action that launches a ChatBot.](./img/ai-action-inpage.svg)
251
279
  </div>
252
280
 
253
- When a ChatBot is launches via an AI-supported action, the action should be sent as a user message once the ChatBot opens.
281
+ When a ChatBot is launched via an AI-supported action, the action should be sent as a user message once the ChatBot opens.
254
282
 
255
283
  <div class="ws-docs-content-img">
256
284
  ![User message in ChatBot for an AI action command.](./img/ai-action-message.svg)
257
285
  </div>
258
286
 
259
- ### Starting a new conversation
287
+ ### Starting a new chat
288
+
289
+ Each time a user begins a new chat, display a [welcome message](#welcome-message), with prompts that provide initial suggestions and indicate the actions that the ChatBot can take.
290
+
291
+ The default approach for users to create a new chat is by clicking the "New chat" button (which contains a "pen to square" icon) placed at the top of the [chat history menu](#using-the-chat-history-menu).
260
292
 
261
- Each time a user begins a new conversation, display a [welcome message, with prompts](#welcome-message) that help them learn what the ChatBot can help with.
293
+ <div class="ws-docs-content-img">
294
+ ![A blue "New chat" button at the top right of a drawer labeled "Chat history".](./img/new-chat-in-nav.svg)
295
+ </div>
296
+
297
+ Alternatively, you can choose to surface the "New chat" button as an icon button in the header. For this approach, the "pen to square" icon is displayed in the button and a "New chat" tooltip should appear on hover and focus.
262
298
 
263
- As much as possible, the suggested prompts should consider the user’s location in the service or application, or the situation their project is undergoing.
299
+ <div class="ws-docs-content-img">
300
+ ![An icon button is placed at the start of the ChatBot header, prior to a hamburger menu. It contains the visual of a pen placed within a square and is in a hover state, with a darker gray background and a black tooltip that says "New chat."](./img/starting-new-chat.svg)
301
+ </div>
264
302
 
265
303
  ### Executing user requests
266
304
 
@@ -272,9 +310,9 @@ This can be done using the [quick response](/extensions/chatbot/messages#message
272
310
  ![Confirmation options from a bot in response to a user's request.](./img/quick-response-confirmation.svg)
273
311
  </div>
274
312
 
275
- ### Using the conversation history menu
313
+ ### Using the chat history menu
276
314
 
277
- The ChatBot history menu contains a log of a users' previous chats. Clicking the menu icon opens a side drawer in the ChatBot window.
315
+ The ChatBot history menu contains a log of a user's previous chats. Clicking the menu icon opens a side drawer in the ChatBot window.
278
316
 
279
317
  By clicking into the history menu, users can search through previous conversations and perform additional actions, such as sharing a conversation with others.
280
318
 
@@ -282,13 +320,13 @@ By clicking into the history menu, users can search through previous conversatio
282
320
  ![Conversation history with an options menu opened on a previous conversation.](./img/conversation-history.svg)
283
321
  </div>
284
322
 
285
- When the conversation history is still loading, display skeleton items:
323
+ When the chat history is still loading, display skeleton items:
286
324
 
287
325
  <div class="ws-docs-content-img">
288
326
  ![Chat history items loading.](./img/loading-state.svg)
289
327
  </div>
290
328
 
291
- If there's an error loading the conversation history, display an error screen with steps for resolving the error:
329
+ If there's an error loading the chat history, display an error screen with steps for resolving the error:
292
330
 
293
331
  <div class="ws-docs-content-img">
294
332
  ![Error state in chat history.](./img/error-state.svg)
@@ -349,9 +387,9 @@ For guidance, refer to our download transcripts demo, which opens a Markdown fil
349
387
 
350
388
  Choose the download action location that best works for your ChatBot:
351
389
 
352
- #### Download via conversation history drawer
390
+ #### Download via chat history drawer
353
391
 
354
- If your ChatBot uses a conversation history drawer, you can provide a download option in the [actions menu linked to a previous conversation](/extensions/chatbot/ui#drawer-with-conversation-actions).
392
+ If your ChatBot uses a chat history drawer, you can provide a download option in the [actions menu linked to a previous conversation](/extensions/chatbot/ui#drawer-with-conversation-actions).
355
393
 
356
394
  <div class="ws-docs-content-img">
357
395
  ![Expanded menu for previous chat in the history window, which shows a download option.](./img/download-chat-history.svg)
@@ -367,7 +405,7 @@ To allow users to download individual bot messages, the message actions can incl
367
405
 
368
406
  #### Download control in header
369
407
 
370
- If you don't use a conversation history drawer, you can place an option to download the transcript for the active chat within the header options menu.
408
+ If you don't use a chat history drawer, you can place an option to download the transcript for the active chat within the header options menu.
371
409
 
372
410
  <div class="ws-docs-content-img">
373
411
  ![Download transcript action within the ChatBot header options menu.](./img/download-header.svg)
@@ -27,5 +27,18 @@ export const MessageWithDeepThinkingExample: FunctionComponent = () => (
27
27
  body: "Here's why I said this."
28
28
  }}
29
29
  />
30
+ <Message
31
+ name="Bot"
32
+ role="bot"
33
+ avatar={patternflyAvatar}
34
+ content="This example has deep thinking that is loading:"
35
+ deepThinking={{
36
+ isDefaultExpanded: false,
37
+ toggleContent: 'Show thinking',
38
+ subheading: 'Thought for 3 seconds',
39
+ body: "Here's why I said this.",
40
+ isLoading: true
41
+ }}
42
+ />
30
43
  </>
31
44
  );