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

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.
Files changed (51) hide show
  1. package/dist/cjs/DeepThinking/DeepThinking.d.ts +5 -1
  2. package/dist/cjs/DeepThinking/DeepThinking.js +2 -2
  3. package/dist/cjs/DeepThinking/DeepThinking.test.js +18 -0
  4. package/dist/cjs/Message/Message.d.ts +4 -0
  5. package/dist/cjs/Message/Message.js +3 -2
  6. package/dist/cjs/Message/Message.test.js +14 -0
  7. package/dist/cjs/SourcesCard/SourcesCard.d.ts +4 -0
  8. package/dist/cjs/SourcesCard/SourcesCard.js +3 -3
  9. package/dist/cjs/SourcesCard/SourcesCard.test.js +12 -0
  10. package/dist/cjs/SourcesCardBase/SourcesCardBase.d.ts +4 -0
  11. package/dist/cjs/SourcesCardBase/SourcesCardBase.js +13 -4
  12. package/dist/cjs/SourcesCardBase/SourcesCardBase.test.js +28 -0
  13. package/dist/css/main.css +16 -0
  14. package/dist/css/main.css.map +1 -1
  15. package/dist/esm/DeepThinking/DeepThinking.d.ts +5 -1
  16. package/dist/esm/DeepThinking/DeepThinking.js +4 -4
  17. package/dist/esm/DeepThinking/DeepThinking.test.js +18 -0
  18. package/dist/esm/Message/Message.d.ts +4 -0
  19. package/dist/esm/Message/Message.js +3 -2
  20. package/dist/esm/Message/Message.test.js +14 -0
  21. package/dist/esm/SourcesCard/SourcesCard.d.ts +4 -0
  22. package/dist/esm/SourcesCard/SourcesCard.js +3 -3
  23. package/dist/esm/SourcesCard/SourcesCard.test.js +12 -0
  24. package/dist/esm/SourcesCardBase/SourcesCardBase.d.ts +4 -0
  25. package/dist/esm/SourcesCardBase/SourcesCardBase.js +13 -4
  26. package/dist/esm/SourcesCardBase/SourcesCardBase.test.js +28 -0
  27. package/package.json +1 -1
  28. package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +57 -19
  29. package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +7 -0
  30. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +13 -0
  31. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithSources.tsx +37 -0
  32. package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +14 -0
  33. package/patternfly-docs/content/extensions/chatbot/img/custom-source-card.svg +37 -0
  34. package/patternfly-docs/content/extensions/chatbot/img/new-chat-in-nav.svg +21 -0
  35. package/patternfly-docs/content/extensions/chatbot/img/source-card-expanded.svg +141 -0
  36. package/patternfly-docs/content/extensions/chatbot/img/source-card-summary.svg +83 -0
  37. package/patternfly-docs/content/extensions/chatbot/img/source-card.svg +76 -0
  38. package/patternfly-docs/content/extensions/chatbot/img/source-tile-expanded.svg +134 -0
  39. package/patternfly-docs/content/extensions/chatbot/img/source-tile-summary.svg +82 -0
  40. package/patternfly-docs/content/extensions/chatbot/img/source-tile.svg +30 -17
  41. package/patternfly-docs/content/extensions/chatbot/img/starting-new-chat.svg +57 -0
  42. package/src/DeepThinking/DeepThinking.test.tsx +23 -0
  43. package/src/DeepThinking/DeepThinking.tsx +16 -3
  44. package/src/Message/Message.scss +9 -0
  45. package/src/Message/Message.test.tsx +21 -0
  46. package/src/Message/Message.tsx +23 -14
  47. package/src/SourcesCard/SourcesCard.scss +13 -1
  48. package/src/SourcesCard/SourcesCard.test.tsx +20 -0
  49. package/src/SourcesCard/SourcesCard.tsx +9 -3
  50. package/src/SourcesCardBase/SourcesCardBase.test.tsx +49 -0
  51. package/src/SourcesCardBase/SourcesCardBase.tsx +72 -3
@@ -19,4 +19,16 @@ describe('SourcesCard', () => {
19
19
  screen.getByRole('button', { name: /Go to previous page/i });
20
20
  screen.getByRole('button', { name: /Go to next page/i });
21
21
  });
22
+ it('should render with wrap layout when layout is set to wrap', () => {
23
+ render(_jsx(SourcesCard, { layout: "wrap", sources: [
24
+ { title: 'How to make an apple pie', link: '' },
25
+ { title: 'How to make cookies', link: '' },
26
+ { title: 'How to make a sandwich', link: '' }
27
+ ] }));
28
+ expect(screen.getByText('How to make an apple pie')).toBeVisible();
29
+ expect(screen.getByText('How to make cookies')).toBeVisible();
30
+ expect(screen.getByText('How to make a sandwich')).toBeVisible();
31
+ expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
32
+ expect(screen.queryByText('1/3')).not.toBeInTheDocument();
33
+ });
22
34
  });
@@ -3,12 +3,16 @@ import { ButtonProps, CardBodyProps, CardFooterProps, CardProps, CardTitleProps,
3
3
  export interface SourcesCardBaseProps extends CardProps {
4
4
  /** Additional classes for the pagination navigation container. */
5
5
  className?: string;
6
+ /** The layout used to display source cards. Use wrap to display and wrap all sources at once. */
7
+ layout?: 'paginated' | 'wrap';
6
8
  /** Flag indicating if the pagination is disabled. */
7
9
  isDisabled?: boolean;
8
10
  /** @deprecated ofWord has been deprecated. Label for the English word "of." */
9
11
  ofWord?: string;
10
12
  /** Accessible label for the pagination component. */
11
13
  paginationAriaLabel?: string;
14
+ /** Max width of a source card when the wrap layout is used. Can be any valid CSS width value. */
15
+ cardMaxWidth?: string;
12
16
  /** Content rendered inside the paginated card */
13
17
  sources: {
14
18
  /** Title of sources card */
@@ -16,7 +16,7 @@ import { Button, ButtonVariant, Card, CardBody, CardFooter, CardTitle, Expandabl
16
16
  import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
17
17
  const SourcesCardBase = (_a) => {
18
18
  var _b;
19
- var { className, isDisabled, paginationAriaLabel = 'Pagination', sources, toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage, showMoreWords = 'show more', showLessWords = 'show less', isCompact, cardTitleProps, cardBodyProps, cardFooterProps } = _a, props = __rest(_a, ["className", "isDisabled", "paginationAriaLabel", "sources", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage", "showMoreWords", "showLessWords", "isCompact", "cardTitleProps", "cardBodyProps", "cardFooterProps"]);
19
+ var { className, isDisabled, paginationAriaLabel = 'Pagination', sources, toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage, showMoreWords = 'show more', showLessWords = 'show less', isCompact, cardTitleProps, cardBodyProps, cardFooterProps, layout = 'paginated', cardMaxWidth = '400px' } = _a, props = __rest(_a, ["className", "isDisabled", "paginationAriaLabel", "sources", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage", "showMoreWords", "showLessWords", "isCompact", "cardTitleProps", "cardBodyProps", "cardFooterProps", "layout", "cardMaxWidth"]);
20
20
  const [page, setPage] = useState(1);
21
21
  const [isExpanded, setIsExpanded] = useState(false);
22
22
  const onToggle = (_event, isExpanded) => {
@@ -26,13 +26,22 @@ const SourcesCardBase = (_a) => {
26
26
  setPage(newPage);
27
27
  onSetPage && onSetPage(_evt, newPage);
28
28
  };
29
- const renderTitle = (title, truncateProps) => {
29
+ const renderTitle = (title, index, truncateProps) => {
30
30
  if (title) {
31
31
  return _jsx(Truncate, Object.assign({ content: title }, truncateProps));
32
32
  }
33
- return `Source ${page}`;
33
+ return `Source ${index !== undefined ? index + 1 : page}`;
34
34
  };
35
- return (_jsx("div", { className: "pf-chatbot__sources-card-base", children: _jsxs(Card, Object.assign({ isCompact: isCompact, className: "pf-chatbot__sources-card" }, props, { children: [_jsx(CardTitle, Object.assign({ className: "pf-chatbot__sources-card-title" }, cardTitleProps, { children: _jsxs("div", { className: "pf-chatbot__sources-card-title-container", children: [_jsx(Button, Object.assign({ component: "a", variant: ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? _jsx(ExternalLinkSquareAltIcon, {}) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined, onClick: (_b = sources[page - 1].onClick) !== null && _b !== void 0 ? _b : undefined }, sources[page - 1].titleProps, { children: renderTitle(sources[page - 1].title, sources[page - 1].truncateProps) })), sources[page - 1].subtitle && (_jsx("span", { className: "pf-chatbot__sources-card-subtitle", children: sources[page - 1].subtitle }))] }) })), sources[page - 1].body && (_jsx(CardBody, Object.assign({ className: `pf-chatbot__sources-card-body ${sources[page - 1].footer ? 'pf-chatbot__compact-sources-card-body' : undefined}` }, cardBodyProps, { children: sources[page - 1].hasShowMore ? (
35
+ const renderUncontrolledSourceCard = (source, index) => {
36
+ var _a;
37
+ return (_jsx("li", { className: "pf-chatbot__sources-list-item", children: _jsxs(Card, Object.assign({ isCompact: isCompact, className: "pf-chatbot__sources-card", style: { maxWidth: cardMaxWidth } }, props, { children: [_jsx(CardTitle, Object.assign({ className: "pf-chatbot__sources-card-title" }, cardTitleProps, { children: _jsxs("div", { className: "pf-chatbot__sources-card-title-container", children: [_jsx(Button, Object.assign({ component: "a", variant: ButtonVariant.link, href: source.link, icon: source.isExternal ? _jsx(ExternalLinkSquareAltIcon, {}) : undefined, iconPosition: "end", isInline: true, rel: source.isExternal ? 'noreferrer' : undefined, target: source.isExternal ? '_blank' : undefined, onClick: (_a = source.onClick) !== null && _a !== void 0 ? _a : undefined }, source.titleProps, { children: renderTitle(source.title, index, source.truncateProps) })), source.subtitle && _jsx("span", { className: "pf-chatbot__sources-card-subtitle", children: source.subtitle })] }) })), source.body && (_jsx(CardBody, Object.assign({ className: `pf-chatbot__sources-card-body ${source.footer ? 'pf-chatbot__compact-sources-card-body' : undefined}` }, cardBodyProps, { children: source.hasShowMore ? (
38
+ // prevents extra VO announcements of button text - parent Message has aria-live
39
+ _jsx("div", { "aria-live": "off", children: _jsx(ExpandableSection, { variant: ExpandableSectionVariant.truncate, toggleTextCollapsed: showMoreWords, toggleTextExpanded: showLessWords, truncateMaxLines: 2, children: source.body }) })) : (_jsx("div", { className: "pf-chatbot__sources-card-body-text", children: source.body })) }))), source.footer && (_jsx(CardFooter, Object.assign({ className: "pf-chatbot__sources-card-footer" }, cardFooterProps, { children: source.footer })))] })) }, index));
40
+ };
41
+ if (layout === 'wrap') {
42
+ return (_jsx("div", { className: "pf-chatbot__sources-card-base pf-m-wrap", children: _jsx("ul", { className: "pf-chatbot__sources-list", role: "list", children: sources.map((source, index) => renderUncontrolledSourceCard(source, index)) }) }));
43
+ }
44
+ return (_jsx("div", { className: "pf-chatbot__sources-card-base", children: _jsxs(Card, Object.assign({ isCompact: isCompact, className: "pf-chatbot__sources-card" }, props, { children: [_jsx(CardTitle, Object.assign({ className: "pf-chatbot__sources-card-title" }, cardTitleProps, { children: _jsxs("div", { className: "pf-chatbot__sources-card-title-container", children: [_jsx(Button, Object.assign({ component: "a", variant: ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? _jsx(ExternalLinkSquareAltIcon, {}) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined, onClick: (_b = sources[page - 1].onClick) !== null && _b !== void 0 ? _b : undefined }, sources[page - 1].titleProps, { children: renderTitle(sources[page - 1].title, undefined, sources[page - 1].truncateProps) })), sources[page - 1].subtitle && (_jsx("span", { className: "pf-chatbot__sources-card-subtitle", children: sources[page - 1].subtitle }))] }) })), sources[page - 1].body && (_jsx(CardBody, Object.assign({ className: `pf-chatbot__sources-card-body ${sources[page - 1].footer ? 'pf-chatbot__compact-sources-card-body' : undefined}` }, cardBodyProps, { children: sources[page - 1].hasShowMore ? (
36
45
  // prevents extra VO announcements of button text - parent Message has aria-live
37
46
  _jsx("div", { "aria-live": "off", children: _jsx(ExpandableSection, { variant: ExpandableSectionVariant.truncate, toggleText: isExpanded ? showLessWords : showMoreWords, onToggle: onToggle, isExpanded: isExpanded, truncateMaxLines: 2, children: sources[page - 1].body }) })) : (_jsx("div", { className: "pf-chatbot__sources-card-body-text", children: sources[page - 1].body })) }))), sources[page - 1].footer ? (_jsx(CardFooter, Object.assign({ className: "pf-chatbot__sources-card-footer" }, cardFooterProps, { children: sources[page - 1].footer }))) : (sources.length > 1 && (_jsx(CardFooter, Object.assign({ className: "pf-chatbot__sources-card-footer-container" }, cardFooterProps, { children: _jsx("div", { className: "pf-chatbot__sources-card-footer", children: _jsxs("nav", { className: `pf-chatbot__sources-card-footer-buttons ${className}`, "aria-label": paginationAriaLabel, children: [_jsx(Button, { variant: ButtonVariant.plain, isDisabled: isDisabled || page === 1, "data-action": "previous", onClick: (event) => {
38
47
  const newPage = page >= 1 ? page - 1 : 1;
@@ -163,4 +163,32 @@ describe('SourcesCardBase', () => {
163
163
  render(_jsx(SourcesCardBase, { sources: [{ title: 'How to make an apple pie', link: '', titleProps: { className: 'test' } }] }));
164
164
  expect(screen.getByRole('link', { name: /How to make an apple pie/i })).toHaveClass('test');
165
165
  });
166
+ it('should render with wrap layout when layout prop is set to wrap', () => {
167
+ render(_jsx(SourcesCardBase, { layout: "wrap", sources: [
168
+ { title: 'How to make an apple pie', link: '' },
169
+ { title: 'How to make cookies', link: '' },
170
+ { title: 'How to make a sandwich', link: '' }
171
+ ] }));
172
+ expect(screen.getByText('How to make an apple pie')).toBeVisible();
173
+ expect(screen.getByText('How to make cookies')).toBeVisible();
174
+ expect(screen.getByText('How to make a sandwich')).toBeVisible();
175
+ expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
176
+ expect(screen.queryByText('1/3')).not.toBeInTheDocument();
177
+ });
178
+ it('should apply default cardMaxWidth when using wrap layout', () => {
179
+ render(_jsx(SourcesCardBase, { layout: "wrap", sources: [
180
+ { title: 'How to make an apple pie', link: '' },
181
+ { title: 'How to make cookies', link: '' }
182
+ ] }));
183
+ const firstCard = screen.getByText('How to make an apple pie').closest('.pf-chatbot__sources-card');
184
+ expect(firstCard).toHaveStyle({ maxWidth: '400px' });
185
+ });
186
+ it('should apply custom cardMaxWidth when using wrap layout', () => {
187
+ render(_jsx(SourcesCardBase, { layout: "wrap", sources: [
188
+ { title: 'How to make an apple pie', link: '' },
189
+ { title: 'How to make cookies', link: '' }
190
+ ], cardMaxWidth: "500px" }));
191
+ const firstCard = screen.getByText('How to make an apple pie').closest('.pf-chatbot__sources-card');
192
+ expect(firstCard).toHaveStyle({ maxWidth: '500px' });
193
+ });
166
194
  });
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.3",
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)
@@ -319,6 +319,13 @@ _Italic text, formatted with single underscores_
319
319
  hasRoundAvatar={false}
320
320
  />
321
321
  <Message name="Bot" role="bot" content="This is a message from a bot with no avatar." />
322
+ <Message
323
+ name="Bot"
324
+ role="bot"
325
+ avatar={patternflyAvatar}
326
+ isMetadataVisible={false}
327
+ content="This is a message from a bot with metadata not visible."
328
+ />
322
329
  <Select
323
330
  id="single-select"
324
331
  isOpen={isOpen}
@@ -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
  );
@@ -241,6 +241,43 @@ export const MessageWithSourcesExample: FunctionComponent = () => {
241
241
  }}
242
242
  isCompact
243
243
  />
244
+
245
+ <Message
246
+ name="Bot"
247
+ role="bot"
248
+ avatar={patternflyAvatar}
249
+ content="This example demonstrates the non-paginated layout option. When enabled, all source cards are displayed in a flex layout that wraps automatically based on available space:"
250
+ sources={{
251
+ sources: [
252
+ {
253
+ title: 'Getting started with Red Hat OpenShift',
254
+ link: '#',
255
+ body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud.',
256
+ isExternal: true,
257
+ hasShowMore: true
258
+ },
259
+ {
260
+ title: 'Azure Red Hat OpenShift documentation',
261
+ link: '#',
262
+ body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure.',
263
+ isExternal: true
264
+ },
265
+ {
266
+ title: 'OKD Documentation: Home',
267
+ link: '#',
268
+ body: 'OKD is a distribution of Kubernetes optimized for continuous application development and multi-tenant deployment.',
269
+ isExternal: true
270
+ },
271
+ {
272
+ title: 'Red Hat OpenShift Container Platform',
273
+ link: '#',
274
+ body: 'Red Hat OpenShift Container Platform is a Kubernetes platform that provides a cloud-like experience anywhere it is deployed.',
275
+ isExternal: true
276
+ }
277
+ ],
278
+ layout: 'wrap'
279
+ }}
280
+ />
244
281
  </>
245
282
  );
246
283
  };
@@ -334,6 +334,13 @@ _Italic text, formatted with single underscores_
334
334
  avatarProps={{ isBordered: true }}
335
335
  />
336
336
  <Message name="User" role="user" content="This is a user message with no avatar" />
337
+ <Message
338
+ name="User"
339
+ role="user"
340
+ content="This is a user message with metadata not visible."
341
+ avatar={userAvatar}
342
+ isMetadataVisible={false}
343
+ />
337
344
  <Message
338
345
  name="User"
339
346
  role="user"
@@ -345,6 +352,13 @@ _Italic text, formatted with single underscores_
345
352
  avatar={userAvatar}
346
353
  inputRef={messageInputRef}
347
354
  />
355
+ <Message
356
+ name="User"
357
+ role="user"
358
+ avatar={userAvatar}
359
+ alignment="end"
360
+ content="This is a user message that is aligned at the end of the message container."
361
+ />
348
362
  <Select
349
363
  id="single-select"
350
364
  isOpen={isOpen}