@patternfly/chatbot 2.1.0 → 2.2.0-prerelease.10

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 (177) hide show
  1. package/dist/cjs/Chatbot/Chatbot.js +0 -9
  2. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +5 -1
  3. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +4 -4
  4. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +3 -3
  5. package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.d.ts +17 -0
  6. package/dist/cjs/ChatbotHeader/ChatbotHeaderCloseButton.js +14 -0
  7. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.d.ts +2 -0
  8. package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +2 -2
  9. package/dist/cjs/ChatbotHeader/index.d.ts +1 -0
  10. package/dist/cjs/ChatbotHeader/index.js +1 -0
  11. package/dist/cjs/CodeModal/CodeModal.js +2 -12
  12. package/dist/cjs/Message/ListMessage/OrderedListMessage.d.ts +1 -1
  13. package/dist/cjs/Message/ListMessage/OrderedListMessage.js +2 -2
  14. package/dist/cjs/Message/Message.d.ts +16 -6
  15. package/dist/cjs/Message/Message.js +6 -6
  16. package/dist/cjs/Message/Message.test.js +51 -0
  17. package/dist/cjs/Message/QuickResponse/QuickResponse.d.ts +15 -0
  18. package/dist/cjs/Message/QuickResponse/QuickResponse.js +33 -0
  19. package/dist/cjs/Message/QuickStarts/FallbackImg.d.ts +13 -0
  20. package/dist/cjs/Message/QuickStarts/FallbackImg.js +34 -0
  21. package/dist/cjs/Message/QuickStarts/QuickStartTile.d.ts +27 -0
  22. package/dist/cjs/Message/QuickStarts/QuickStartTile.js +82 -0
  23. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.d.ts +23 -0
  24. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.js +64 -0
  25. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.test.d.ts +1 -0
  26. package/dist/cjs/Message/QuickStarts/QuickStartTileDescription.test.js +76 -0
  27. package/dist/cjs/Message/QuickStarts/QuickStartTileHeader.d.ts +11 -0
  28. package/dist/cjs/Message/QuickStarts/QuickStartTileHeader.js +30 -0
  29. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.d.ts +30 -0
  30. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.js +77 -0
  31. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart.d.ts +30 -0
  32. package/dist/cjs/Message/QuickStarts/monitor-sampleapp-quickstart.js +77 -0
  33. package/dist/cjs/Message/QuickStarts/types.d.ts +132 -0
  34. package/dist/cjs/Message/QuickStarts/types.js +17 -0
  35. package/dist/cjs/MessageBar/SendButton.js +1 -1
  36. package/dist/cjs/ResponseActions/ResponseActionButton.d.ts +6 -0
  37. package/dist/cjs/ResponseActions/ResponseActionButton.js +10 -2
  38. package/dist/cjs/ResponseActions/ResponseActionButton.test.d.ts +1 -0
  39. package/dist/cjs/ResponseActions/ResponseActionButton.test.js +54 -0
  40. package/dist/cjs/ResponseActions/ResponseActions.d.ts +4 -0
  41. package/dist/cjs/ResponseActions/ResponseActions.js +26 -9
  42. package/dist/cjs/ResponseActions/ResponseActions.test.js +79 -5
  43. package/dist/cjs/Settings/SettingsForm.d.ts +13 -0
  44. package/dist/cjs/Settings/SettingsForm.js +27 -0
  45. package/dist/cjs/Settings/index.d.ts +2 -0
  46. package/dist/cjs/Settings/index.js +23 -0
  47. package/dist/cjs/TermsOfUse/TermsOfUse.d.ts +34 -0
  48. package/dist/cjs/TermsOfUse/TermsOfUse.js +49 -0
  49. package/dist/cjs/TermsOfUse/TermsOfUse.test.d.ts +1 -0
  50. package/dist/cjs/TermsOfUse/TermsOfUse.test.js +79 -0
  51. package/dist/cjs/TermsOfUse/index.d.ts +2 -0
  52. package/dist/cjs/TermsOfUse/index.js +23 -0
  53. package/dist/cjs/index.d.ts +4 -0
  54. package/dist/cjs/index.js +7 -1
  55. package/dist/css/main.css +191 -30
  56. package/dist/css/main.css.map +1 -1
  57. package/dist/dynamic/Settings/package.json +1 -0
  58. package/dist/dynamic/TermsOfUse/package.json +1 -0
  59. package/dist/esm/Chatbot/Chatbot.js +0 -9
  60. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +5 -1
  61. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +4 -4
  62. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +3 -3
  63. package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.d.ts +17 -0
  64. package/dist/esm/ChatbotHeader/ChatbotHeaderCloseButton.js +8 -0
  65. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.d.ts +2 -0
  66. package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +2 -2
  67. package/dist/esm/ChatbotHeader/index.d.ts +1 -0
  68. package/dist/esm/ChatbotHeader/index.js +1 -0
  69. package/dist/esm/CodeModal/CodeModal.js +2 -12
  70. package/dist/esm/Message/ListMessage/OrderedListMessage.d.ts +1 -1
  71. package/dist/esm/Message/ListMessage/OrderedListMessage.js +2 -2
  72. package/dist/esm/Message/Message.d.ts +16 -6
  73. package/dist/esm/Message/Message.js +7 -7
  74. package/dist/esm/Message/Message.test.js +51 -0
  75. package/dist/esm/Message/QuickResponse/QuickResponse.d.ts +15 -0
  76. package/dist/esm/Message/QuickResponse/QuickResponse.js +26 -0
  77. package/dist/esm/Message/QuickStarts/FallbackImg.d.ts +13 -0
  78. package/dist/esm/Message/QuickStarts/FallbackImg.js +9 -0
  79. package/dist/esm/Message/QuickStarts/QuickStartTile.d.ts +27 -0
  80. package/dist/esm/Message/QuickStarts/QuickStartTile.js +52 -0
  81. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.d.ts +23 -0
  82. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.js +35 -0
  83. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.test.d.ts +1 -0
  84. package/dist/esm/Message/QuickStarts/QuickStartTileDescription.test.js +48 -0
  85. package/dist/esm/Message/QuickStarts/QuickStartTileHeader.d.ts +11 -0
  86. package/dist/esm/Message/QuickStarts/QuickStartTileHeader.js +5 -0
  87. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.d.ts +30 -0
  88. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.js +74 -0
  89. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart.d.ts +30 -0
  90. package/dist/esm/Message/QuickStarts/monitor-sampleapp-quickstart.js +74 -0
  91. package/dist/esm/Message/QuickStarts/types.d.ts +132 -0
  92. package/dist/esm/Message/QuickStarts/types.js +14 -0
  93. package/dist/esm/MessageBar/SendButton.js +1 -1
  94. package/dist/esm/ResponseActions/ResponseActionButton.d.ts +6 -0
  95. package/dist/esm/ResponseActions/ResponseActionButton.js +10 -2
  96. package/dist/esm/ResponseActions/ResponseActionButton.test.d.ts +1 -0
  97. package/dist/esm/ResponseActions/ResponseActionButton.test.js +49 -0
  98. package/dist/esm/ResponseActions/ResponseActions.d.ts +4 -0
  99. package/dist/esm/ResponseActions/ResponseActions.js +26 -9
  100. package/dist/esm/ResponseActions/ResponseActions.test.js +79 -5
  101. package/dist/esm/Settings/SettingsForm.d.ts +13 -0
  102. package/dist/esm/Settings/SettingsForm.js +20 -0
  103. package/dist/esm/Settings/index.d.ts +2 -0
  104. package/dist/esm/Settings/index.js +2 -0
  105. package/dist/esm/TermsOfUse/TermsOfUse.d.ts +34 -0
  106. package/dist/esm/TermsOfUse/TermsOfUse.js +42 -0
  107. package/dist/esm/TermsOfUse/TermsOfUse.test.d.ts +1 -0
  108. package/dist/esm/TermsOfUse/TermsOfUse.test.js +74 -0
  109. package/dist/esm/TermsOfUse/index.d.ts +2 -0
  110. package/dist/esm/TermsOfUse/index.js +2 -0
  111. package/dist/esm/index.d.ts +4 -0
  112. package/dist/esm/index.js +4 -0
  113. package/dist/tsconfig.tsbuildinfo +1 -1
  114. package/package.json +7 -13
  115. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomResponseActions.tsx +4 -0
  116. package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx +31 -0
  117. package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +26 -4
  118. package/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts +65 -0
  119. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotFooter.tsx +1 -1
  120. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotFootnote.tsx +2 -2
  121. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawer.tsx +2 -2
  122. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerNavigation.tsx +67 -0
  123. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSelection.tsx +78 -0
  124. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarDisabled.tsx +26 -0
  125. package/patternfly-docs/content/extensions/chatbot/examples/UI/PF-TermsAndConditionsHeader.svg +148 -0
  126. package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +289 -0
  127. package/patternfly-docs/content/extensions/chatbot/examples/UI/SquareChatbotToggle.tsx +1 -1
  128. package/patternfly-docs/content/extensions/chatbot/examples/UI/TermsOfUse.tsx +147 -0
  129. package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +56 -0
  130. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +2 -2
  131. package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx +2 -2
  132. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachment.tsx +20 -19
  133. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +1 -1
  134. package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedChatbot.tsx +2 -2
  135. package/src/Chatbot/Chatbot.scss +0 -10
  136. package/src/Chatbot/Chatbot.tsx +0 -9
  137. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +14 -0
  138. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +3 -3
  139. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +11 -3
  140. package/src/ChatbotFooter/ChatbotFooter.scss +2 -1
  141. package/src/ChatbotHeader/ChatbotHeaderCloseButton.tsx +51 -0
  142. package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +5 -2
  143. package/src/ChatbotHeader/index.ts +1 -0
  144. package/src/CodeModal/CodeModal.scss +8 -0
  145. package/src/CodeModal/CodeModal.tsx +2 -13
  146. package/src/FileDropZone/__snapshots__/FileDropZone.test.tsx.snap +1 -1
  147. package/src/Message/ListMessage/OrderedListMessage.tsx +2 -2
  148. package/src/Message/Message.scss +0 -14
  149. package/src/Message/Message.test.tsx +76 -0
  150. package/src/Message/Message.tsx +35 -26
  151. package/src/Message/QuickResponse/QuickResponse.scss +33 -0
  152. package/src/Message/QuickResponse/QuickResponse.tsx +50 -0
  153. package/src/Message/QuickStarts/FallbackImg.tsx +24 -0
  154. package/src/Message/QuickStarts/QuickStartTile.scss +25 -0
  155. package/src/Message/QuickStarts/QuickStartTile.tsx +147 -0
  156. package/src/Message/QuickStarts/QuickStartTileDescription.test.tsx +57 -0
  157. package/src/Message/QuickStarts/QuickStartTileDescription.tsx +81 -0
  158. package/src/Message/QuickStarts/QuickStartTileHeader.tsx +21 -0
  159. package/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts +75 -0
  160. package/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts +75 -0
  161. package/src/Message/QuickStarts/types.ts +154 -0
  162. package/src/MessageBar/SendButton.scss +24 -0
  163. package/src/MessageBar/SendButton.tsx +1 -1
  164. package/src/ResponseActions/ResponseActionButton.test.tsx +52 -0
  165. package/src/ResponseActions/ResponseActionButton.tsx +46 -27
  166. package/src/ResponseActions/ResponseActions.scss +10 -8
  167. package/src/ResponseActions/ResponseActions.test.tsx +103 -5
  168. package/src/ResponseActions/ResponseActions.tsx +54 -7
  169. package/src/Settings/Settings.scss +34 -0
  170. package/src/Settings/SettingsForm.tsx +25 -0
  171. package/src/Settings/index.ts +3 -0
  172. package/src/TermsOfUse/TermsOfUse.scss +66 -0
  173. package/src/TermsOfUse/TermsOfUse.test.tsx +138 -0
  174. package/src/TermsOfUse/TermsOfUse.tsx +117 -0
  175. package/src/TermsOfUse/index.ts +3 -0
  176. package/src/index.ts +6 -0
  177. package/src/main.scss +7 -3
@@ -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
+ }
@@ -0,0 +1,147 @@
1
+ import * as React from 'react';
2
+ import RocketIcon from '@patternfly/react-icons/dist/js/icons/rocket-icon';
3
+ import OutlinedBookmarkIcon from '@patternfly/react-icons/dist/js/icons/outlined-bookmark-icon';
4
+ import {
5
+ Card,
6
+ CardBody,
7
+ CardHeader,
8
+ CardFooter,
9
+ CardTitle,
10
+ Icon,
11
+ Button,
12
+ Flex,
13
+ Stack,
14
+ Label,
15
+ pluralize
16
+ } from '@patternfly/react-core';
17
+ import OutlinedClockIcon from '@patternfly/react-icons/dist/js/icons/outlined-clock-icon';
18
+ import QuickStartTileHeader from './QuickStartTileHeader';
19
+ import QuickStartTileDescription from './QuickStartTileDescription';
20
+ import { QuickStart, QuickstartAction } from './types';
21
+ import FallbackImg from './FallbackImg';
22
+
23
+ export const camelize = (str: string) =>
24
+ str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function (match, index) {
25
+ if (+match === 0) {
26
+ return '';
27
+ } // or if (/\s+/.test(match)) for white spaces
28
+ return index === 0 ? match.toLowerCase() : match.toUpperCase();
29
+ });
30
+
31
+ export interface QuickStartTileProps {
32
+ /** ClassName applied to the card */
33
+ className?: string;
34
+ /** The quickstart object triggered by this tile */
35
+ quickStart: QuickStart;
36
+ /** Event handler attached to the tile */
37
+ onClick?: () => void;
38
+ /** Action config for button rendered next to title */
39
+ action?: QuickstartAction;
40
+ /** Callback that returns active quick start value when clicked */
41
+ onSelectQuickStart: (id?: string) => void;
42
+ /** Label for the English word "minute". */
43
+ minuteWord?: string;
44
+ /** Label for the English word "minutes". */
45
+ minuteWordPlural?: string;
46
+ /** Label for the English word "Prerequisite" */
47
+ prerequisiteWord?: string;
48
+ /** Label for the English word "Prerequisites" */
49
+ prerequisiteWordPlural?: string;
50
+ /** Aria-label for the quick start description button */
51
+ quickStartButtonAriaLabel?: string;
52
+ }
53
+
54
+ const QuickStartTile: React.FC<QuickStartTileProps> = ({
55
+ className,
56
+ quickStart,
57
+ onClick,
58
+ onSelectQuickStart,
59
+ minuteWord = 'minute',
60
+ minuteWordPlural = 'minutes',
61
+ prerequisiteWord,
62
+ prerequisiteWordPlural,
63
+ quickStartButtonAriaLabel,
64
+ action
65
+ }) => {
66
+ const {
67
+ metadata: { name: id },
68
+ spec: { icon, displayName, description, durationMinutes, prerequisites, link, type }
69
+ } = quickStart;
70
+
71
+ let quickStartIcon: React.ReactNode;
72
+ if (typeof icon === 'object') {
73
+ quickStartIcon = <Icon size="2xl">{icon}</Icon>;
74
+ } else {
75
+ quickStartIcon = (
76
+ <Icon size="2xl">
77
+ <FallbackImg src={icon as string} alt="" className="pfext-catalog-item-icon__img" fallback={<RocketIcon />} />
78
+ </Icon>
79
+ );
80
+ }
81
+
82
+ const onSelect = () => {
83
+ if (!link) {
84
+ onSelectQuickStart(id);
85
+ } else {
86
+ window.open(link.href, '_blank', 'noopener,noreferrer');
87
+ }
88
+ onClick && onClick();
89
+ };
90
+
91
+ const ActionIcon = action?.icon || OutlinedBookmarkIcon;
92
+ const additionalAction = action ? (
93
+ <Button
94
+ aria-label={action['aria-label']}
95
+ icon={<ActionIcon />}
96
+ variant="plain"
97
+ onClick={action.onClick}
98
+ {...action.buttonProps}
99
+ />
100
+ ) : undefined;
101
+
102
+ return (
103
+ <Card
104
+ className={`pf-chatbot__quickstarts-tile ${className ? className : ''}`}
105
+ id={`${id}-chatbot-qs-tile`}
106
+ style={{ height: '100%' }}
107
+ data-testid={`chatbot-qs-card-${camelize(displayName)}`}
108
+ >
109
+ <CardHeader
110
+ {...(action && {
111
+ actions: { actions: additionalAction }
112
+ })}
113
+ >
114
+ {quickStartIcon}
115
+ </CardHeader>
116
+ <CardTitle>
117
+ <QuickStartTileHeader name={displayName} onSelect={onSelect} quickStartId={id} />
118
+ </CardTitle>
119
+ <CardBody>
120
+ <Stack hasGutter>
121
+ <Flex spaceItems={{ default: 'spaceItemsSm' }}>
122
+ {type && <Label color={type.color}>{type.text}</Label>}
123
+ {durationMinutes && (
124
+ <Label variant="outline" data-test="duration" icon={<OutlinedClockIcon />}>
125
+ {pluralize(durationMinutes, minuteWord, minuteWordPlural)}
126
+ </Label>
127
+ )}
128
+ </Flex>
129
+ <QuickStartTileDescription
130
+ description={description}
131
+ prerequisites={prerequisites}
132
+ prerequisiteWord={prerequisiteWord}
133
+ prerequisiteWordPlural={prerequisiteWordPlural}
134
+ quickStartButtonAriaLabel={quickStartButtonAriaLabel}
135
+ />
136
+ </Stack>
137
+ </CardBody>
138
+ <CardFooter>
139
+ <Button variant="link" isInline onClick={onSelect}>
140
+ <span className="pf-v6-c-button__text">Start</span>
141
+ </Button>
142
+ </CardFooter>
143
+ </Card>
144
+ );
145
+ };
146
+
147
+ export default QuickStartTile;
@@ -0,0 +1,57 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { monitorSampleAppQuickStart } from './monitor-sampleapp-quickstart';
6
+ import QuickStartTileDescription, { pluralizeWord } from './QuickStartTileDescription';
7
+
8
+ describe('pluralizeWord function', () => {
9
+ it('should render no plural correctly', () => {
10
+ expect(pluralizeWord(2, 'pizza')).toBe('pizzas');
11
+ });
12
+ });
13
+
14
+ describe('QuickStart tile description', () => {
15
+ it('should render no prereqs correctly', () => {
16
+ render(<QuickStartTileDescription description={monitorSampleAppQuickStart.spec.description} />);
17
+ expect(screen.queryByRole('heading')).toBeFalsy();
18
+ });
19
+ it('should render singular prereq correctly', () => {
20
+ render(
21
+ <QuickStartTileDescription
22
+ description={monitorSampleAppQuickStart.spec.description}
23
+ prerequisites={[`You completed the "Getting started with a sample" quick start.`]}
24
+ />
25
+ );
26
+ expect(screen.getByRole('heading', { name: /1 Prerequisite/i })).toBeTruthy();
27
+ expect(screen.getByRole('button', { name: /Show prerequisite/i })).toBeTruthy();
28
+ });
29
+ it('should render plural prereq correctly', () => {
30
+ render(
31
+ <QuickStartTileDescription
32
+ description={monitorSampleAppQuickStart.spec.description}
33
+ prerequisites={[
34
+ `You completed the "Getting started with a sample" quick start.`,
35
+ `You completed the app quick start`
36
+ ]}
37
+ />
38
+ );
39
+ expect(screen.getByRole('heading', { name: /2 Prerequisites/i })).toBeTruthy();
40
+ expect(screen.getByRole('button', { name: /Show prerequisites/i })).toBeTruthy();
41
+ });
42
+ it('should be able to click prereqs link', async () => {
43
+ render(
44
+ <QuickStartTileDescription
45
+ description={monitorSampleAppQuickStart.spec.description}
46
+ prerequisites={[`You completed the "Getting started with a sample" quick start.`]}
47
+ />
48
+ );
49
+ const button = screen.getByRole('button', { name: /Show prerequisites/i });
50
+ expect(screen.queryByRole('dialog', { name: /Prerequisite/i })).toBeFalsy();
51
+ await userEvent.click(button);
52
+
53
+ expect(screen.getByRole('dialog', { name: /Prerequisite/i })).toBeTruthy();
54
+ expect(screen.getByRole('button', { name: /Close/i })).toBeTruthy();
55
+ expect(screen.getByText(/You completed the "Getting started with a sample" quick start./i)).toBeTruthy();
56
+ });
57
+ });
@@ -0,0 +1,81 @@
1
+ import * as React from 'react';
2
+ import { Button, Flex, pluralize, Popover } from '@patternfly/react-core';
3
+ import InfoCircleIcon from '@patternfly/react-icons/dist/js/icons/info-circle-icon';
4
+
5
+ interface QuickStartTileDescriptionProps {
6
+ /** QuickStart description */
7
+ description: string;
8
+ /** QuickStart prerequisites */
9
+ prerequisites?: string[];
10
+ /** Label for the English word "Prerequisite" */
11
+ prerequisiteWord?: string;
12
+ /** Label for the English word "Prerequisites" */
13
+ prerequisiteWordPlural?: string;
14
+ /** Aria-label for the quick start button */
15
+ quickStartButtonAriaLabel?: string;
16
+ }
17
+
18
+ /** This function is a helper for pluralizing strings stolen from React.
19
+ *
20
+ * @param {number} i The quantity of the string you want to pluralize
21
+ * @param {string} singular The singular version of the string
22
+ * @param {string} plural The change to the string that should occur if the quantity is not equal to 1.
23
+ * Defaults to adding an 's'.
24
+ */
25
+ export function pluralizeWord(i: number, singular: string, plural?: string) {
26
+ if (!plural) {
27
+ plural = `${singular}s`;
28
+ }
29
+ return `${i === 1 ? singular : plural}`;
30
+ }
31
+
32
+ const QuickStartTileDescription: React.FC<QuickStartTileDescriptionProps> = ({
33
+ description,
34
+ prerequisites,
35
+ prerequisiteWord = 'Prerequisite',
36
+ prerequisiteWordPlural = 'Prerequisites',
37
+ quickStartButtonAriaLabel = 'Show prerequisites'
38
+ }) => {
39
+ const prereqs = prerequisites?.filter((p) => p);
40
+ const buttonRef = React.useRef<HTMLButtonElement>(null);
41
+ const pluralizedPrereq = pluralizeWord(prereqs?.length || 0, prerequisiteWord, prerequisiteWordPlural);
42
+ return (
43
+ <>
44
+ {description}
45
+ {prereqs && prereqs.length > 0 && (
46
+ <Flex spaceItems={{ default: 'spaceItemsSm' }}>
47
+ <h5>{pluralize(prereqs.length, prerequisiteWord, prerequisiteWordPlural)}</h5>
48
+ <Button
49
+ variant="link"
50
+ isInline
51
+ data-testid="qs-card-prereqs"
52
+ ref={buttonRef}
53
+ onClick={(e) => {
54
+ e.preventDefault();
55
+ e.stopPropagation();
56
+ }}
57
+ aria-label={quickStartButtonAriaLabel}
58
+ >
59
+ <InfoCircleIcon />
60
+ </Button>
61
+ <Popover
62
+ aria-label={pluralizedPrereq}
63
+ headerContent={pluralizedPrereq}
64
+ triggerRef={buttonRef}
65
+ bodyContent={
66
+ <div>
67
+ <ul aria-label={pluralizedPrereq}>
68
+ {prereqs.map((prerequisite, index) => (
69
+ // eslint-disable-next-line react/no-array-index-key
70
+ <li key={index}>{prerequisite}</li>
71
+ ))}
72
+ </ul>
73
+ </div>
74
+ }
75
+ />
76
+ </Flex>
77
+ )}
78
+ </>
79
+ );
80
+ };
81
+ export default QuickStartTileDescription;
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { Button, Flex } from '@patternfly/react-core';
3
+
4
+ interface QuickStartTileHeaderProps {
5
+ /** Name for the header */
6
+ name: string;
7
+ /** Id for the QuickStart */
8
+ quickStartId?: string;
9
+ /** Callback for when the name of the QuickStart is clicked */
10
+ onSelect: (e: React.FormEvent<HTMLInputElement> | React.MouseEvent<Element, MouseEvent>) => void;
11
+ }
12
+
13
+ const QuickStartTileHeader: React.FC<QuickStartTileHeaderProps> = ({ name, quickStartId, onSelect }) => (
14
+ <Flex flexWrap={{ default: 'nowrap' }}>
15
+ <Button data-test="title" id={quickStartId} variant="link" isInline onClick={onSelect}>
16
+ {name}
17
+ </Button>
18
+ </Flex>
19
+ );
20
+
21
+ export default QuickStartTileHeader;
@@ -0,0 +1,75 @@
1
+ export const monitorSampleAppQuickStartWithImage = {
2
+ apiVersion: 'console.openshift.io/v1',
3
+ kind: 'QuickStarts',
4
+ metadata: {
5
+ name: 'monitor-sampleapp'
6
+ },
7
+ spec: {
8
+ icon: 'test.png', // this is only difference
9
+ version: 4.7,
10
+ displayName: 'Monitoring your sample application',
11
+ durationMinutes: 10,
12
+ description: `Now that you’ve created a sample application and added health checks, let’s monitor your application.`,
13
+ prerequisites: [`You completed the "Getting started with a sample" quick start.`],
14
+ introduction: `### This quick start shows you how to monitor your sample application.
15
+ You should have previously created the **sample-app** application and **nodejs-sample** deployment via the **Get started with a sample** quick start. If you haven't, you may be able to follow these tasks with any existing deployment.`,
16
+ tasks: [
17
+ {
18
+ title: `Viewing the monitoring details of your sample application`,
19
+ description: `### To view the details of your sample application:
20
+ 1. Go to the project your sample application was created in.
21
+ 2. In the **</> Developer** perspective, go to **Topology** view.
22
+ 3. Click on the **nodejs-sample** deployment to view its details.
23
+ 4. Click on the **Monitoring** tab in the side panel.
24
+ You can see context sensitive metrics and alerts in the **Monitoring** tab.`,
25
+ review: {
26
+ instructions: `#### To verify you can view the monitoring information:
27
+ 1. Do you see a **Metrics** accordion in the side panel?
28
+ 2. Do you see a **View monitoring dashboard** link in the **Metrics** accordion?
29
+ 3. Do you see three charts in the **Metrics** accordion: **CPU Usage**, **Memory Usage** and **Receive Bandwidth**?`,
30
+ failedTaskHelp: `This task isn’t verified yet. Try the task again.`
31
+ },
32
+ summary: {
33
+ success: `You have learned how you can monitor your sample app!`,
34
+ failed: `Try the steps again.`
35
+ }
36
+ },
37
+ {
38
+ title: `Viewing your project monitoring dashboard`,
39
+ description: `### To view the project monitoring dashboard in the context of **nodejs-sample**:
40
+ 1. Click on the **View monitoring dashboard** link in the side panel.
41
+ 2. You can change the **Time Range** and **Refresh Interval** of the dashboard.
42
+ 3. You can change the context of the dashboard as well by clicking on the drop-down list. Select a specific workload or **All Workloads** to view the dashboard in the context of the entire project.`,
43
+ review: {
44
+ instructions: `#### To verify that you are able to view the monitoring dashboard:
45
+ Do you see metrics charts in the dashboard?`,
46
+ failedTaskHelp: `This task isn’t verified yet. Try the task again.`
47
+ },
48
+ summary: {
49
+ success: `You have learned how to view the dashboard in the context of your sample app!`,
50
+ failed: `Try the steps again.`
51
+ }
52
+ },
53
+ {
54
+ title: `Viewing custom metrics`,
55
+ description: `### To view custom metrics:
56
+ 1. Click on the **Metrics** tab of the **Monitoring** page.
57
+ 2. Click the **Select Query** drop-down list to see the available queries.
58
+ 3. Click on **Filesystem Usage** from the list to run the query.`,
59
+ review: {
60
+ instructions: `#### Verify you can see the chart associated with the query:
61
+ Do you see a chart displayed with filesystem usage for your project? Note: select **Custom Query** from the dropdown to create and run a custom query utilizing PromQL.
62
+ `,
63
+ failedTaskHelp: `This task isn’t verified yet. Try the task again.`
64
+ },
65
+ summary: {
66
+ success: `You have learned how to run a query!`,
67
+ failed: `Try the steps again.`
68
+ }
69
+ }
70
+ ],
71
+ conclusion: `You have learned how to access workload monitoring and metrics!`,
72
+
73
+ nextQuickStart: [``]
74
+ }
75
+ };