@patternfly/chatbot 2.2.0-prerelease.1 → 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.
Files changed (187) hide show
  1. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +19 -1
  2. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +11 -11
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +39 -3
  4. package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.d.ts +17 -0
  5. package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.js +14 -0
  6. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.d.ts +2 -0
  7. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +2 -2
  8. package/dist/cjs/ChatbotHeader/index.d.ts +1 -0
  9. package/dist/cjs/ChatbotHeader/index.js +1 -0
  10. package/dist/cjs/CodeModal/CodeModal.js +2 -12
  11. package/dist/cjs/Compare/Compare.d.ts +17 -0
  12. package/dist/cjs/Compare/Compare.js +50 -0
  13. package/dist/cjs/Compare/Compare.test.d.ts +1 -0
  14. package/dist/cjs/Compare/Compare.test.js +20 -0
  15. package/dist/cjs/Compare/index.d.ts +2 -0
  16. package/dist/cjs/Compare/index.js +23 -0
  17. package/dist/cjs/Message/ListMessage/OrderedListMessage.d.ts +1 -1
  18. package/dist/cjs/Message/ListMessage/OrderedListMessage.js +2 -2
  19. package/dist/cjs/Message/Message.d.ts +16 -6
  20. package/dist/cjs/Message/Message.js +6 -6
  21. package/dist/cjs/Message/Message.test.js +51 -0
  22. package/dist/cjs/Message/QuickResponse/QuickResponse.d.ts +15 -0
  23. package/dist/cjs/Message/QuickResponse/QuickResponse.js +33 -0
  24. package/dist/cjs/Message/QuickStarts/FallbackImg.d.ts +13 -0
  25. package/dist/cjs/Message/QuickStarts/FallbackImg.js +34 -0
  26. package/dist/cjs/Message/QuickStarts/QuickStartTile.d.ts +27 -0
  27. package/dist/cjs/Message/QuickStarts/QuickStartTile.js +82 -0
  28. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.d.ts +23 -0
  29. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.js +64 -0
  30. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.test.d.ts +1 -0
  31. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.test.js +76 -0
  32. package/dist/cjs/Message/QuickStarts/QuickStartTileHeader.d.ts +11 -0
  33. package/dist/cjs/Message/QuickStarts/QuickStartTileHeader.js +30 -0
  34. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.d.ts +30 -0
  35. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.js +77 -0
  36. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart.d.ts +30 -0
  37. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart.js +77 -0
  38. package/dist/cjs/Message/QuickStarts/types.d.ts +132 -0
  39. package/dist/cjs/Message/QuickStarts/types.js +17 -0
  40. package/dist/cjs/ResponseActions/ResponseActionButton.d.ts +6 -0
  41. package/dist/cjs/ResponseActions/ResponseActionButton.js +10 -2
  42. package/dist/cjs/ResponseActions/ResponseActionButton.test.d.ts +1 -0
  43. package/dist/cjs/ResponseActions/ResponseActionButton.test.js +54 -0
  44. package/dist/cjs/ResponseActions/ResponseActions.d.ts +4 -0
  45. package/dist/cjs/ResponseActions/ResponseActions.js +26 -9
  46. package/dist/cjs/ResponseActions/ResponseActions.test.js +79 -5
  47. package/dist/cjs/Settings/SettingsForm.d.ts +13 -0
  48. package/dist/cjs/Settings/SettingsForm.js +27 -0
  49. package/dist/cjs/Settings/index.d.ts +2 -0
  50. package/dist/cjs/Settings/index.js +23 -0
  51. package/dist/cjs/TermsOfUse/TermsOfUse.d.ts +34 -0
  52. package/dist/cjs/TermsOfUse/TermsOfUse.js +49 -0
  53. package/dist/cjs/TermsOfUse/TermsOfUse.test.d.ts +1 -0
  54. package/dist/cjs/TermsOfUse/TermsOfUse.test.js +79 -0
  55. package/dist/cjs/TermsOfUse/index.d.ts +2 -0
  56. package/dist/cjs/TermsOfUse/index.js +23 -0
  57. package/dist/cjs/index.d.ts +6 -0
  58. package/dist/cjs/index.js +10 -1
  59. package/dist/css/main.css +244 -18
  60. package/dist/css/main.css.map +1 -1
  61. package/dist/dynamic/Compare/package.json +1 -0
  62. package/dist/dynamic/Settings/package.json +1 -0
  63. package/dist/dynamic/TermsOfUse/package.json +1 -0
  64. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +19 -1
  65. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +11 -11
  66. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +39 -3
  67. package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.d.ts +17 -0
  68. package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.js +8 -0
  69. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.d.ts +2 -0
  70. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +2 -2
  71. package/dist/esm/ChatbotHeader/index.d.ts +1 -0
  72. package/dist/esm/ChatbotHeader/index.js +1 -0
  73. package/dist/esm/CodeModal/CodeModal.js +2 -12
  74. package/dist/esm/Compare/Compare.d.ts +17 -0
  75. package/dist/esm/Compare/Compare.js +43 -0
  76. package/dist/esm/Compare/Compare.test.d.ts +1 -0
  77. package/dist/esm/Compare/Compare.test.js +15 -0
  78. package/dist/esm/Compare/index.d.ts +2 -0
  79. package/dist/esm/Compare/index.js +2 -0
  80. package/dist/esm/Message/ListMessage/OrderedListMessage.d.ts +1 -1
  81. package/dist/esm/Message/ListMessage/OrderedListMessage.js +2 -2
  82. package/dist/esm/Message/Message.d.ts +16 -6
  83. package/dist/esm/Message/Message.js +7 -7
  84. package/dist/esm/Message/Message.test.js +51 -0
  85. package/dist/esm/Message/QuickResponse/QuickResponse.d.ts +15 -0
  86. package/dist/esm/Message/QuickResponse/QuickResponse.js +26 -0
  87. package/dist/esm/Message/QuickStarts/FallbackImg.d.ts +13 -0
  88. package/dist/esm/Message/QuickStarts/FallbackImg.js +9 -0
  89. package/dist/esm/Message/QuickStarts/QuickStartTile.d.ts +27 -0
  90. package/dist/esm/Message/QuickStarts/QuickStartTile.js +52 -0
  91. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.d.ts +23 -0
  92. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.js +35 -0
  93. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.test.d.ts +1 -0
  94. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.test.js +48 -0
  95. package/dist/esm/Message/QuickStarts/QuickStartTileHeader.d.ts +11 -0
  96. package/dist/esm/Message/QuickStarts/QuickStartTileHeader.js +5 -0
  97. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.d.ts +30 -0
  98. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.js +74 -0
  99. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart.d.ts +30 -0
  100. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart.js +74 -0
  101. package/dist/esm/Message/QuickStarts/types.d.ts +132 -0
  102. package/dist/esm/Message/QuickStarts/types.js +14 -0
  103. package/dist/esm/ResponseActions/ResponseActionButton.d.ts +6 -0
  104. package/dist/esm/ResponseActions/ResponseActionButton.js +10 -2
  105. package/dist/esm/ResponseActions/ResponseActionButton.test.d.ts +1 -0
  106. package/dist/esm/ResponseActions/ResponseActionButton.test.js +49 -0
  107. package/dist/esm/ResponseActions/ResponseActions.d.ts +4 -0
  108. package/dist/esm/ResponseActions/ResponseActions.js +26 -9
  109. package/dist/esm/ResponseActions/ResponseActions.test.js +79 -5
  110. package/dist/esm/Settings/SettingsForm.d.ts +13 -0
  111. package/dist/esm/Settings/SettingsForm.js +20 -0
  112. package/dist/esm/Settings/index.d.ts +2 -0
  113. package/dist/esm/Settings/index.js +2 -0
  114. package/dist/esm/TermsOfUse/TermsOfUse.d.ts +34 -0
  115. package/dist/esm/TermsOfUse/TermsOfUse.js +42 -0
  116. package/dist/esm/TermsOfUse/TermsOfUse.test.d.ts +1 -0
  117. package/dist/esm/TermsOfUse/TermsOfUse.test.js +74 -0
  118. package/dist/esm/TermsOfUse/index.d.ts +2 -0
  119. package/dist/esm/TermsOfUse/index.js +2 -0
  120. package/dist/esm/index.d.ts +6 -0
  121. package/dist/esm/index.js +6 -0
  122. package/dist/tsconfig.tsbuildinfo +1 -1
  123. package/package.json +7 -13
  124. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomResponseActions.tsx +4 -0
  125. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx +31 -0
  126. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +26 -4
  127. package/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts +65 -0
  128. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotFooter.tsx +1 -1
  129. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotFootnote.tsx +2 -2
  130. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +2 -2
  131. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerNavigation.tsx +67 -0
  132. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerResizable.tsx +94 -0
  133. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSelection.tsx +78 -0
  134. package/patternfly-docs/content/extensions/chatbot/examples/UI/PF-TermsAndConditionsHeader.svg +148 -0
  135. package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +289 -0
  136. package/patternfly-docs/content/extensions/chatbot/examples/UI/SquareChatbotToggle.tsx +1 -1
  137. package/patternfly-docs/content/extensions/chatbot/examples/UI/TermsOfUse.tsx +147 -0
  138. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +54 -0
  139. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +26 -3
  140. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx +2 -2
  141. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachment.tsx +20 -19
  142. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +1 -1
  143. package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedChatbot.tsx +2 -2
  144. package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedComparisonChatbot.tsx +206 -0
  145. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +14 -0
  146. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +112 -3
  147. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +46 -9
  148. package/src/ChatbotFooter/ChatbotFooter.scss +2 -1
  149. package/src/ChatbotHeader/ChatbotHeaderCloseButton.tsx +51 -0
  150. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +5 -2
  151. package/src/ChatbotHeader/index.ts +1 -0
  152. package/src/CodeModal/CodeModal.scss +8 -0
  153. package/src/CodeModal/CodeModal.tsx +2 -13
  154. package/src/Compare/Compare.scss +72 -0
  155. package/src/Compare/Compare.test.tsx +31 -0
  156. package/src/Compare/Compare.tsx +98 -0
  157. package/src/Compare/index.ts +2 -0
  158. package/src/FileDropZone/__snapshots__/FileDropZone.test.tsx.snap +1 -1
  159. package/src/Message/ListMessage/OrderedListMessage.tsx +2 -2
  160. package/src/Message/Message.scss +0 -14
  161. package/src/Message/Message.test.tsx +76 -0
  162. package/src/Message/Message.tsx +35 -26
  163. package/src/Message/QuickResponse/QuickResponse.scss +33 -0
  164. package/src/Message/QuickResponse/QuickResponse.tsx +50 -0
  165. package/src/Message/QuickStarts/FallbackImg.tsx +24 -0
  166. package/src/Message/QuickStarts/QuickStartTile.scss +25 -0
  167. package/src/Message/QuickStarts/QuickStartTile.tsx +147 -0
  168. package/src/Message/QuickStarts/QuickStartTileDescription.test.tsx +57 -0
  169. package/src/Message/QuickStarts/QuickStartTileDescription.tsx +81 -0
  170. package/src/Message/QuickStarts/QuickStartTileHeader.tsx +21 -0
  171. package/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts +75 -0
  172. package/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts +75 -0
  173. package/src/Message/QuickStarts/types.ts +154 -0
  174. package/src/ResponseActions/ResponseActionButton.test.tsx +52 -0
  175. package/src/ResponseActions/ResponseActionButton.tsx +46 -27
  176. package/src/ResponseActions/ResponseActions.scss +10 -8
  177. package/src/ResponseActions/ResponseActions.test.tsx +103 -5
  178. package/src/ResponseActions/ResponseActions.tsx +54 -7
  179. package/src/Settings/Settings.scss +34 -0
  180. package/src/Settings/SettingsForm.tsx +25 -0
  181. package/src/Settings/index.ts +3 -0
  182. package/src/TermsOfUse/TermsOfUse.scss +66 -0
  183. package/src/TermsOfUse/TermsOfUse.test.tsx +138 -0
  184. package/src/TermsOfUse/TermsOfUse.tsx +117 -0
  185. package/src/TermsOfUse/index.ts +3 -0
  186. package/src/index.ts +9 -0
  187. package/src/main.scss +5 -0
@@ -0,0 +1,72 @@
1
+ .pf-chatbot__compare-container {
2
+ display: flex;
3
+ flex-direction: column;
4
+ position: relative;
5
+ height: 100%;
6
+ }
7
+ .pf-chatbot__compare-toggle {
8
+ width: 100%;
9
+
10
+ .pf-v6-c-toggle-group__button {
11
+ width: 100%;
12
+ display: flex;
13
+ justify-content: center;
14
+ }
15
+ }
16
+ .pf-chatbot__compare {
17
+ display: flex;
18
+ height: 100%;
19
+ width: 100%;
20
+
21
+ @media screen and (max-width: 900px) {
22
+ overflow-y: auto;
23
+ }
24
+
25
+ .pf-chatbot__compare-item:first-of-type {
26
+ border-right: 1px solid var(--pf-t--global--border--color--default);
27
+
28
+ @media screen and (max-width: 900px) {
29
+ border-right: 0px;
30
+ }
31
+ }
32
+ }
33
+
34
+ .pf-chatbot__compare-item {
35
+ flex: 1;
36
+
37
+ .pf-chatbot--embedded .pf-chatbot__messagebox {
38
+ width: 100%;
39
+ }
40
+
41
+ .pf-chatbot__content {
42
+ padding: 0;
43
+ }
44
+
45
+ .pf-chatbot.pf-chatbot--embedded {
46
+ @media screen and (max-width: 900px) {
47
+ height: 100%;
48
+ }
49
+ }
50
+ }
51
+ .pf-chatbot__compare-item-hidden {
52
+ display: block;
53
+
54
+ @media screen and (max-width: 900px) {
55
+ display: none;
56
+ }
57
+ }
58
+
59
+ .pf-chatbot__compare-mobile-controls {
60
+ padding: var(--pf-t--global--spacer--md) var(--pf-t--global--spacer--lg) 0 var(--pf-t--global--spacer--lg);
61
+ display: none;
62
+ background-color: var(--pf-t--global--background--color--secondary--default);
63
+ position: sticky;
64
+ top: 0;
65
+ z-index: 9999;
66
+
67
+ @media screen and (max-width: 900px) {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: var(--pf-t--global--spacer--md);
71
+ }
72
+ }
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import Compare from './Compare';
5
+
6
+ const firstChild = (
7
+ <div>
8
+ <h1>Child 1</h1>
9
+ </div>
10
+ );
11
+
12
+ const secondChild = (
13
+ <div>
14
+ <h1>Child 2</h1>
15
+ </div>
16
+ );
17
+
18
+ describe('Compare', () => {
19
+ it('should render compare correctly', () => {
20
+ render(
21
+ <Compare
22
+ firstChildDisplayName="Child 1"
23
+ secondChildDisplayName="Child 2"
24
+ firstChild={firstChild}
25
+ secondChild={secondChild}
26
+ />
27
+ );
28
+ expect(screen.getByRole('heading', { name: /Child 1/i })).toBeTruthy();
29
+ expect(screen.getByRole('heading', { name: /Child 2/i })).toBeTruthy();
30
+ });
31
+ });
@@ -0,0 +1,98 @@
1
+ import React, { PropsWithChildren } from 'react';
2
+ import { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
3
+
4
+ interface CompareProps {
5
+ /** First of two children to render */
6
+ firstChild: React.ReactNode;
7
+ /** Second of two children to render */
8
+ secondChild: React.ReactNode;
9
+ /** Display name for first child, used in mobile toggle */
10
+ firstChildDisplayName: string;
11
+ /** Display name for second child, used in mobile toggle */
12
+ secondChildDisplayName: string;
13
+ /** Aria label for mobile toggle group */
14
+ toggleGroupAriaLabel?: string;
15
+ /** Callback for when mobile toggle is used */
16
+ onToggleClick?: (event: MouseEvent | React.MouseEvent<any, MouseEvent> | React.KeyboardEvent<Element>) => void;
17
+ }
18
+
19
+ export const Compare = ({
20
+ firstChild,
21
+ secondChild,
22
+ firstChildDisplayName,
23
+ secondChildDisplayName,
24
+ onToggleClick,
25
+ toggleGroupAriaLabel = 'Select which chatbot to display'
26
+ }: PropsWithChildren<CompareProps>) => {
27
+ const [isSelected, setIsSelected] = React.useState('toggle-group-chatbot-1');
28
+ const [showFirstChatbot, setShowFirstChatbot] = React.useState(true);
29
+ const [showSecondChatbot, setShowSecondChatbot] = React.useState(false);
30
+
31
+ React.useEffect(() => {
32
+ // we want to show the first if we switch to the mobile toggle view
33
+ // and reset/switch back to normal otherwise
34
+ const updateChatbotVisibility = () => {
35
+ if (window.innerWidth >= 901) {
36
+ setShowFirstChatbot(true);
37
+ setShowSecondChatbot(true);
38
+ } else {
39
+ setShowFirstChatbot(true);
40
+ setShowSecondChatbot(false);
41
+ setIsSelected('toggle-group-chatbot-1');
42
+ }
43
+ };
44
+ window.addEventListener('resize', updateChatbotVisibility);
45
+
46
+ return () => {
47
+ window.removeEventListener('resize', updateChatbotVisibility);
48
+ };
49
+ }, []);
50
+
51
+ // this only happens on mobile
52
+ const handleChildToggleClick = (
53
+ event: MouseEvent | React.MouseEvent<any, MouseEvent> | React.KeyboardEvent<Element>
54
+ ) => {
55
+ const id = event.currentTarget.id;
56
+ setIsSelected(id);
57
+ setShowSecondChatbot(!showSecondChatbot);
58
+ setShowFirstChatbot(!showFirstChatbot);
59
+ onToggleClick && onToggleClick(event);
60
+ };
61
+
62
+ return (
63
+ <>
64
+ <div className="pf-chatbot__compare-mobile-controls">
65
+ <ToggleGroup aria-label={toggleGroupAriaLabel}>
66
+ <ToggleGroupItem
67
+ className="pf-chatbot__compare-toggle"
68
+ text={firstChildDisplayName}
69
+ buttonId="toggle-group-chatbot-1"
70
+ isSelected={isSelected === 'toggle-group-chatbot-1'}
71
+ onChange={handleChildToggleClick}
72
+ />
73
+ <ToggleGroupItem
74
+ className="pf-chatbot__compare-toggle"
75
+ text={secondChildDisplayName}
76
+ buttonId="toggle-group-chatbot-2"
77
+ isSelected={isSelected === 'toggle-group-chatbot-2'}
78
+ onChange={handleChildToggleClick}
79
+ />
80
+ </ToggleGroup>
81
+ </div>
82
+ <div className="pf-chatbot__compare">
83
+ <div
84
+ className={`pf-chatbot__compare-item ${!showFirstChatbot ? 'pf-chatbot__compare-item-hidden' : undefined}`}
85
+ >
86
+ {firstChild}
87
+ </div>
88
+ <div
89
+ className={`pf-chatbot__compare-item ${!showSecondChatbot ? 'pf-chatbot__compare-item-hidden' : undefined}`}
90
+ >
91
+ {secondChild}
92
+ </div>
93
+ </div>
94
+ </>
95
+ );
96
+ };
97
+
98
+ export default Compare;
@@ -0,0 +1,2 @@
1
+ export { default } from './Compare';
2
+ export * from './Compare';
@@ -9,7 +9,7 @@ exports[`FileDropZone should render file drop zone 1`] = `
9
9
  >
10
10
  <input
11
11
  multiple=""
12
- style="display: none;"
12
+ style="border: 0px; clip: rect(0px, 0px, 0px, 0px); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
13
13
  tabindex="-1"
14
14
  type="file"
15
15
  />
@@ -6,9 +6,9 @@ import React from 'react';
6
6
  import { ExtraProps } from 'react-markdown';
7
7
  import { List, ListComponent, OrderType } from '@patternfly/react-core';
8
8
 
9
- const OrderedListMessage = ({ children }: JSX.IntrinsicElements['ol'] & ExtraProps) => (
9
+ const OrderedListMessage = ({ children, start }: JSX.IntrinsicElements['ol'] & ExtraProps) => (
10
10
  <div className="pf-chatbot__message-ordered-list">
11
- <List component={ListComponent.ol} type={OrderType.number}>
11
+ <List component={ListComponent.ol} type={OrderType.number} start={start}>
12
12
  {children}
13
13
  </List>
14
14
  </div>
@@ -95,20 +95,6 @@
95
95
  display: grid;
96
96
  gap: var(--pf-t--global--spacer--sm);
97
97
  }
98
-
99
- &-quick-response {
100
- .pf-v6-c-label {
101
- --pf-v6-c-label--FontSize: var(--pf-t--global--font--size--md);
102
-
103
- @media screen and (min-width: 401px) and (max-width: 600px) {
104
- --pf-v6-c-label__text--MaxWidth: 20ch;
105
- }
106
-
107
- @media screen and (max-width: 400px) {
108
- --pf-v6-c-label__text--MaxWidth: 15ch;
109
- }
110
- }
111
- }
112
98
  }
113
99
 
114
100
  // Attachments
@@ -3,6 +3,8 @@ import { render, screen } from '@testing-library/react';
3
3
  import '@testing-library/jest-dom';
4
4
  import Message from './Message';
5
5
  import userEvent from '@testing-library/user-event';
6
+ import { monitorSampleAppQuickStart } from './QuickStarts/monitor-sampleapp-quickstart';
7
+ import { monitorSampleAppQuickStartWithImage } from './QuickStarts/monitor-sampleapp-quickstart-with-image';
6
8
 
7
9
  const ALL_ACTIONS = [
8
10
  { label: /Good response/i },
@@ -53,6 +55,22 @@ spec:
53
55
 
54
56
  const INLINE_CODE = `Here is an inline code - \`() => void\``;
55
57
 
58
+ const ORDERED_LIST_WITH_CODE = `
59
+ 1. Item 1
60
+ 2. Item 2
61
+
62
+ \`\`\`yaml
63
+ - name: Hello World Playbook
64
+ hosts: localhost
65
+ tasks:
66
+ - name: Print Hello World
67
+ ansible.builtin.debug:
68
+ msg: "Hello, World!"
69
+ \`\`\`
70
+
71
+ 3. Item 3
72
+ `;
73
+
56
74
  const checkListItemsRendered = () => {
57
75
  const items = ['Item 1', 'Item 2', 'Item 3'];
58
76
  expect(screen.getAllByRole('listitem')).toHaveLength(3);
@@ -344,6 +362,12 @@ describe('Message', () => {
344
362
  expect(screen.getByText('Here is an ordered list:')).toBeTruthy();
345
363
  checkListItemsRendered();
346
364
  });
365
+ it('should render ordered lists correctly if there is interstitial content', () => {
366
+ render(<Message avatar="./img" role="user" name="User" content={ORDERED_LIST_WITH_CODE} />);
367
+ checkListItemsRendered();
368
+ const list = screen.getAllByRole('list')[1];
369
+ expect(list).toHaveAttribute('start', '3');
370
+ });
347
371
  it('should render inline code', () => {
348
372
  render(<Message avatar="./img" role="user" name="User" content={INLINE_CODE} />);
349
373
  expect(screen.getByText(/() => void/i)).toBeTruthy();
@@ -415,4 +439,56 @@ describe('Message', () => {
415
439
  expect(screen.getByRole('img')).toHaveClass('test');
416
440
  expect(screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar');
417
441
  });
442
+ it('should handle QuickStart tile correctly', () => {
443
+ render(
444
+ <Message
445
+ avatar="./img"
446
+ role="user"
447
+ name="User"
448
+ content="Hi"
449
+ quickStarts={{
450
+ quickStart: monitorSampleAppQuickStart,
451
+ onSelectQuickStart: (id) => alert(id)
452
+ }}
453
+ />
454
+ );
455
+ expect(screen.getByRole('button', { name: 'Monitoring your sample application' })).toBeTruthy();
456
+ expect(screen.getByRole('heading', { name: '1 Prerequisite' })).toBeTruthy();
457
+ expect(screen.getByRole('button', { name: 'Show prerequisites' })).toBeTruthy();
458
+ expect(screen.getByRole('button', { name: 'Start' })).toBeTruthy();
459
+ });
460
+ it('should handle click on QuickStart tile correctly', async () => {
461
+ const spy = jest.fn();
462
+ render(
463
+ <Message
464
+ avatar="./img"
465
+ role="user"
466
+ name="User"
467
+ content="Hi"
468
+ quickStarts={{
469
+ quickStart: monitorSampleAppQuickStart,
470
+ onSelectQuickStart: (id) => spy(id)
471
+ }}
472
+ />
473
+ );
474
+ await userEvent.click(screen.getByRole('button', { name: 'Monitoring your sample application' }));
475
+ expect(spy).toHaveBeenCalledTimes(1);
476
+ expect(spy).toHaveBeenCalledWith(monitorSampleAppQuickStart.metadata.name);
477
+ });
478
+ it('should handle QuickStart tile with image correctly', async () => {
479
+ const spy = jest.fn();
480
+ render(
481
+ <Message
482
+ avatar="./img"
483
+ role="user"
484
+ name="User"
485
+ content="Hi"
486
+ quickStarts={{
487
+ quickStart: monitorSampleAppQuickStartWithImage,
488
+ onSelectQuickStart: (id) => spy(id)
489
+ }}
490
+ />
491
+ );
492
+ expect(screen.getAllByRole('img')[1]).toHaveAttribute('src', 'test.png');
493
+ });
418
494
  });
@@ -6,16 +6,7 @@ import React from 'react';
6
6
 
7
7
  import Markdown from 'react-markdown';
8
8
  import remarkGfm from 'remark-gfm';
9
- import {
10
- Avatar,
11
- AvatarProps,
12
- Label,
13
- LabelGroup,
14
- LabelGroupProps,
15
- LabelProps,
16
- Timestamp,
17
- Truncate
18
- } from '@patternfly/react-core';
9
+ import { Avatar, AvatarProps, Label, LabelGroupProps, Timestamp, Truncate } from '@patternfly/react-core';
19
10
  import MessageLoading from './MessageLoading';
20
11
  import CodeBlockMessage from './CodeBlockMessage/CodeBlockMessage';
21
12
  import TextMessage from './TextMessage/TextMessage';
@@ -25,12 +16,10 @@ import SourcesCard, { SourcesCardProps } from '../SourcesCard';
25
16
  import ListItemMessage from './ListMessage/ListItemMessage';
26
17
  import UnorderedListMessage from './ListMessage/UnorderedListMessage';
27
18
  import OrderedListMessage from './ListMessage/OrderedListMessage';
19
+ import QuickStartTile from './QuickStarts/QuickStartTile';
20
+ import { QuickStart, QuickstartAction } from './QuickStarts/types';
21
+ import QuickResponse from './QuickResponse/QuickResponse';
28
22
 
29
- export interface QuickResponse extends Omit<LabelProps, 'children'> {
30
- content: string;
31
- id: string;
32
- onClick: () => void;
33
- }
34
23
  export interface MessageAttachment {
35
24
  /** Name of file attached to the message */
36
25
  name: string;
@@ -89,6 +78,19 @@ export interface MessageProps extends Omit<React.HTMLProps<HTMLDivElement>, 'rol
89
78
  hasRoundAvatar?: boolean;
90
79
  /** Any additional props applied to the avatar, for additional customization */
91
80
  avatarProps?: Omit<AvatarProps, 'alt'>;
81
+ /** Props for QuickStart card */
82
+ quickStarts?: {
83
+ quickStart: QuickStart;
84
+ onSelectQuickStart: (id?: string) => void;
85
+ minuteWord?: string;
86
+ minuteWordPlural?: string;
87
+ prerequisiteWord?: string;
88
+ prerequisiteWordPlural?: string;
89
+ quickStartButtonAriaLabel?: string;
90
+ className?: string;
91
+ onClick?: () => void;
92
+ action?: QuickstartAction;
93
+ };
92
94
  }
93
95
 
94
96
  export const Message: React.FunctionComponent<MessageProps> = ({
@@ -108,6 +110,7 @@ export const Message: React.FunctionComponent<MessageProps> = ({
108
110
  attachments,
109
111
  hasRoundAvatar = true,
110
112
  avatarProps,
113
+ quickStarts,
111
114
  ...props
112
115
  }: MessageProps) => {
113
116
  let avatarClassName;
@@ -119,6 +122,7 @@ export const Message: React.FunctionComponent<MessageProps> = ({
119
122
  // Keep timestamps consistent between Timestamp component and aria-label
120
123
  const date = new Date();
121
124
  const dateString = timestamp ?? `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
125
+
122
126
  return (
123
127
  <section
124
128
  aria-label={`Message from ${role} - ${dateString}`}
@@ -156,7 +160,7 @@ export const Message: React.FunctionComponent<MessageProps> = ({
156
160
  p: TextMessage,
157
161
  code: ({ children }) => <CodeBlockMessage {...codeBlockProps}>{children}</CodeBlockMessage>,
158
162
  ul: UnorderedListMessage,
159
- ol: OrderedListMessage,
163
+ ol: (props) => <OrderedListMessage {...props} />,
160
164
  li: ListItemMessage
161
165
  }}
162
166
  remarkPlugins={[remarkGfm]}
@@ -165,18 +169,23 @@ export const Message: React.FunctionComponent<MessageProps> = ({
165
169
  </Markdown>
166
170
  )}
167
171
  {!isLoading && sources && <SourcesCard {...sources} />}
172
+ {quickStarts && quickStarts.quickStart && (
173
+ <QuickStartTile
174
+ quickStart={quickStarts.quickStart}
175
+ onSelectQuickStart={quickStarts.onSelectQuickStart}
176
+ minuteWord={quickStarts.minuteWord}
177
+ minuteWordPlural={quickStarts.minuteWordPlural}
178
+ prerequisiteWord={quickStarts.prerequisiteWord}
179
+ prerequisiteWordPlural={quickStarts.prerequisiteWordPlural}
180
+ quickStartButtonAriaLabel={quickStarts.quickStartButtonAriaLabel}
181
+ />
182
+ )}
168
183
  {!isLoading && actions && <ResponseActions actions={actions} />}
169
184
  {!isLoading && quickResponses && (
170
- <LabelGroup
171
- className={`pf-chatbot__message-quick-response ${quickResponseContainerProps?.className}`}
172
- {...quickResponseContainerProps}
173
- >
174
- {quickResponses.map(({ id, onClick, content, ...props }: QuickResponse) => (
175
- <Label variant="outline" color="blue" key={id} onClick={onClick} {...props}>
176
- {content}
177
- </Label>
178
- ))}
179
- </LabelGroup>
185
+ <QuickResponse
186
+ quickResponses={quickResponses}
187
+ quickResponseContainerProps={quickResponseContainerProps}
188
+ />
180
189
  )}
181
190
  </div>
182
191
  {attachments && (
@@ -0,0 +1,33 @@
1
+ .pf-chatbot__message-quick-response {
2
+ .pf-v6-c-label {
3
+ --pf-v6-c-label--FontSize: var(--pf-t--global--font--size--md);
4
+
5
+ @media screen and (min-width: 401px) and (max-width: 600px) {
6
+ --pf-v6-c-label__text--MaxWidth: 20ch;
7
+ }
8
+
9
+ @media screen and (max-width: 400px) {
10
+ --pf-v6-c-label__text--MaxWidth: 15ch;
11
+ }
12
+ }
13
+
14
+ .pf-chatbot__message-quick-response--selected {
15
+ .pf-v6-c-label__content:is(:hover, :focus) {
16
+ --pf-v6-c-label--m-clickable--hover--BorderWidth: 0;
17
+ --pf-v6-c-label--BackgroundColor: var(--pf-v6-c-label--m-blue--BackgroundColor);
18
+ }
19
+ }
20
+
21
+ .pf-chatbot__message-quick-response--selected:hover,
22
+ .pf-chatbot__message-quick-response--selected:focus {
23
+ --pf-v6-c-label--m-clickable--hover--BorderWidth: 0;
24
+ --pf-v6-c-label--BackgroundColor: var(--pf-v6-c-label--m-blue--BackgroundColor);
25
+ }
26
+
27
+ // active state right before selection
28
+ .pf-v6-c-label.pf-m-blue.pf-m-clickable .pf-v6-c-label__content:is(:active) {
29
+ --pf-v6-c-label--BackgroundColor: var(--pf-v6-c-label--m-blue--BackgroundColor);
30
+ --pf-v6-c-label--m-clickable--hover--BackgroundColor: var(--pf-v6-c-label--m-blue--BackgroundColor);
31
+ --pf-v6-c-label--m-clickable--hover--BorderWidth: 0;
32
+ }
33
+ }
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { Label, LabelGroup, LabelGroupProps, LabelProps } from '@patternfly/react-core';
3
+ import { CheckIcon } from '@patternfly/react-icons';
4
+
5
+ export interface QuickResponse extends Omit<LabelProps, 'children'> {
6
+ content: string;
7
+ id: string;
8
+ onClick: () => void;
9
+ }
10
+
11
+ export interface QuickResponseProps {
12
+ /** Props for quick responses */
13
+ quickResponses: QuickResponse[];
14
+ /** Props for quick responses container */
15
+ quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
16
+ }
17
+
18
+ export const QuickResponse: React.FunctionComponent<QuickResponseProps> = ({
19
+ quickResponses,
20
+ quickResponseContainerProps = { numLabels: 5 }
21
+ }: QuickResponseProps) => {
22
+ const [selectedQuickResponse, setSelectedQuickResponse] = React.useState<string>();
23
+
24
+ const handleQuickResponseClick = (id: string, onClick?: () => void) => {
25
+ setSelectedQuickResponse(id);
26
+ onClick && onClick();
27
+ };
28
+ return (
29
+ <LabelGroup
30
+ className={`pf-chatbot__message-quick-response ${quickResponseContainerProps?.className}`}
31
+ {...quickResponseContainerProps}
32
+ >
33
+ {quickResponses.map(({ id, onClick, content, className, ...props }: QuickResponse) => (
34
+ <Label
35
+ variant={id === selectedQuickResponse ? undefined : 'outline'}
36
+ icon={id === selectedQuickResponse ? <CheckIcon /> : undefined}
37
+ color="blue"
38
+ key={id}
39
+ onClick={() => handleQuickResponseClick(id, onClick)}
40
+ className={`${id === selectedQuickResponse ? 'pf-chatbot__message-quick-response--selected' : ''} ${className ? className : ''}`}
41
+ {...props}
42
+ >
43
+ {content}
44
+ </Label>
45
+ ))}
46
+ </LabelGroup>
47
+ );
48
+ };
49
+
50
+ export default QuickResponse;
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+
3
+ interface FallbackImgProps {
4
+ /** Image source */
5
+ src: string;
6
+ /** Alt text for image */
7
+ alt?: string;
8
+ /** ClassName applied to image */
9
+ className?: string;
10
+ /** Fallback */
11
+ fallback?: React.ReactNode;
12
+ }
13
+
14
+ const FallbackImg: React.FC<FallbackImgProps> = ({ src, alt, className, fallback }) => {
15
+ const [isSrcValid, setIsSrcValid] = React.useState<boolean>(true);
16
+
17
+ if (src && isSrcValid) {
18
+ return <img className={className} src={src} alt={alt} onError={() => setIsSrcValid(false)} />;
19
+ }
20
+
21
+ return <>{fallback}</>;
22
+ };
23
+
24
+ export default FallbackImg;
@@ -0,0 +1,25 @@
1
+ .pf-chatbot__quickstarts-tile {
2
+ min-width: 360px;
3
+ max-width: 650px;
4
+ width: 100%;
5
+
6
+ @media screen and (max-width: 700px) {
7
+ max-width: 100%;
8
+ min-width: initial;
9
+ }
10
+ // some icons provided to catalog tiles might have no defined height/width. Without this style, in those cases
11
+ // the icons would have a height and width of 0.
12
+ .pf-v6-c-card__header-main {
13
+ .pf-v6-c-icon__content {
14
+ display: contents;
15
+ }
16
+ }
17
+ }
18
+
19
+ .pf-v6-theme-dark {
20
+ .pf-chatbot__quickstarts-tile {
21
+ .pfext-catalog-item-icon__img {
22
+ filter: brightness(1.5) invert(1) hue-rotate(180deg) saturate(4);
23
+ }
24
+ }
25
+ }