@patternfly/chatbot 6.5.0-prerelease.1 → 6.5.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 (50) hide show
  1. package/dist/cjs/ChatbotContent/ChatbotContent.d.ts +2 -0
  2. package/dist/cjs/ChatbotContent/ChatbotContent.js +2 -2
  3. package/dist/cjs/ChatbotContent/ChatbotContent.test.js +4 -0
  4. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
  5. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
  6. package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
  7. package/dist/cjs/CodeModal/CodeModal.js +36 -4
  8. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  9. package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
  10. package/dist/cjs/Message/Message.d.ts +4 -19
  11. package/dist/cjs/Message/Message.js +4 -1
  12. package/dist/cjs/Message/Message.test.js +6 -0
  13. package/dist/cjs/__mocks__/rehype-highlight.d.ts +2 -0
  14. package/dist/cjs/__mocks__/rehype-highlight.js +4 -0
  15. package/dist/css/main.css +17 -6
  16. package/dist/css/main.css.map +1 -1
  17. package/dist/esm/ChatbotContent/ChatbotContent.d.ts +2 -0
  18. package/dist/esm/ChatbotContent/ChatbotContent.js +2 -2
  19. package/dist/esm/ChatbotContent/ChatbotContent.test.js +4 -0
  20. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.d.ts +3 -1
  21. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.js +3 -3
  22. package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.js +4 -0
  23. package/dist/esm/CodeModal/CodeModal.js +38 -6
  24. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +3 -1
  25. package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +2 -2
  26. package/dist/esm/Message/Message.d.ts +4 -19
  27. package/dist/esm/Message/Message.js +4 -1
  28. package/dist/esm/Message/Message.test.js +7 -1
  29. package/dist/esm/__mocks__/rehype-highlight.d.ts +2 -0
  30. package/dist/esm/__mocks__/rehype-highlight.js +2 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +2 -1
  33. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithActions.tsx +14 -14
  34. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSelection.tsx +14 -14
  35. package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarAttach.tsx +2 -2
  36. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +2 -2
  37. package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotTranscripts.tsx +1 -1
  38. package/patternfly-docs/patternfly-docs.config.js +1 -0
  39. package/src/ChatbotContent/ChatbotContent.scss +4 -0
  40. package/src/ChatbotContent/ChatbotContent.test.tsx +5 -0
  41. package/src/ChatbotContent/ChatbotContent.tsx +4 -1
  42. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx +5 -0
  43. package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx +7 -4
  44. package/src/CodeModal/CodeModal.tsx +54 -7
  45. package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +3 -2
  46. package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +5 -1
  47. package/src/Message/Message.test.tsx +19 -1
  48. package/src/Message/Message.tsx +6 -22
  49. package/src/Message/TextMessage/TextMessage.scss +6 -0
  50. package/src/__mocks__/rehype-highlight.ts +3 -0
@@ -1,7 +1,8 @@
1
1
  import { ReactNode } from 'react';
2
2
  import type { FunctionComponent, HTMLProps, MouseEvent as ReactMouseEvent, Ref } from 'react';
3
3
  import { Options } from 'react-markdown';
4
- import { AlertProps, AvatarProps, ButtonProps, ExpandableSectionProps, ExpandableSectionToggleProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
4
+ import { AlertProps, AvatarProps, ButtonProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
5
+ import { CodeBlockMessageProps } from './CodeBlockMessage/CodeBlockMessage';
5
6
  import { ActionProps } from '../ResponseActions/ResponseActions';
6
7
  import { SourcesCardProps } from '../SourcesCard';
7
8
  import { QuickStart, QuickstartAction } from './QuickStarts/types';
@@ -9,6 +10,7 @@ import QuickResponse from './QuickResponse/QuickResponse';
9
10
  import { UserFeedbackProps } from './UserFeedback/UserFeedback';
10
11
  import { UserFeedbackCompleteProps } from './UserFeedback/UserFeedbackComplete';
11
12
  import { TableProps } from '@patternfly/react-table';
13
+ import 'highlight.js/styles/vs2015.css';
12
14
  import { PluggableList } from 'unified';
13
15
  import { ToolResponseProps } from '../ToolResponse';
14
16
  import { DeepThinkingProps } from '../DeepThinking';
@@ -69,24 +71,7 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
69
71
  /** Label for the English "Loading message," displayed to screenreaders when loading a message */
70
72
  loadingWord?: string;
71
73
  /** Props for code blocks */
72
- codeBlockProps?: {
73
- /** Aria label applied to code blocks */
74
- 'aria-label'?: string;
75
- /** Class name applied to code blocks */
76
- className?: string;
77
- /** Whether code blocks are expandable */
78
- isExpandable?: boolean;
79
- /** Length of text initially shown in expandable code blocks; defaults to 10 characters */
80
- maxLength?: number;
81
- /** Additional props passed to expandable section if isExpandable is applied */
82
- expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
83
- /** Additional props passed to expandable toggle if isExpandable is applied */
84
- expandableSectionToggleProps?: ExpandableSectionToggleProps;
85
- /** Link text applied to expandable toggle when expanded */
86
- expandedText?: string;
87
- /** Link text applied to expandable toggle when collapsed */
88
- collapsedText?: string;
89
- };
74
+ codeBlockProps?: CodeBlockMessageProps;
90
75
  /** Props for quick responses */
91
76
  quickResponses?: QuickResponse[];
92
77
  /** Props for quick responses container */
@@ -40,6 +40,9 @@ import ImageMessage from './ImageMessage/ImageMessage';
40
40
  import rehypeUnwrapImages from 'rehype-unwrap-images';
41
41
  import rehypeExternalLinks from 'rehype-external-links';
42
42
  import rehypeSanitize from 'rehype-sanitize';
43
+ import rehypeHighlight from 'rehype-highlight';
44
+ // see the full list of styles here: https://highlightjs.org/examples
45
+ import 'highlight.js/styles/vs2015.css';
43
46
  import LinkMessage from './LinkMessage/LinkMessage';
44
47
  import ErrorMessage from './ErrorMessage/ErrorMessage';
45
48
  import MessageInput from './MessageInput';
@@ -55,7 +58,7 @@ export const MessageBase = (_a) => {
55
58
  setMessageText(content);
56
59
  }, [content]);
57
60
  const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
58
- let rehypePlugins = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs];
61
+ let rehypePlugins = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs, rehypeHighlight];
59
62
  if (openLinkInNewTab) {
60
63
  rehypePlugins = rehypePlugins.concat([[rehypeExternalLinks, { target: '_blank' }, rehypeSanitize]]);
61
64
  }
@@ -16,7 +16,7 @@ import userEvent from '@testing-library/user-event';
16
16
  import { monitorSampleAppQuickStart } from './QuickStarts/monitor-sampleapp-quickstart';
17
17
  import { monitorSampleAppQuickStartWithImage } from './QuickStarts/monitor-sampleapp-quickstart-with-image';
18
18
  import rehypeExternalLinks from '../__mocks__/rehype-external-links';
19
- import { AlertActionLink } from '@patternfly/react-core';
19
+ import { AlertActionLink, Button, CodeBlockAction } from '@patternfly/react-core';
20
20
  const ALL_ACTIONS = [
21
21
  { label: /Good response/i },
22
22
  { label: /Bad response/i },
@@ -488,6 +488,12 @@ describe('Message', () => {
488
488
  render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { 'aria-label': 'test' } }));
489
489
  expect(screen.getByRole('button', { name: 'test' })).toBeTruthy();
490
490
  });
491
+ it('should be able to add custom actions to CodeMessage', () => {
492
+ render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: {
493
+ customActions: (_jsx(CodeBlockAction, { children: _jsx(Button, { children: "New custom action" }) }))
494
+ } }));
495
+ expect(screen.getByRole('button', { name: /New custom action/i })).toBeTruthy();
496
+ });
491
497
  it('should handle hasRoundAvatar correctly when it is true', () => {
492
498
  render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: "Hi", hasRoundAvatar: true }));
493
499
  expect(screen.getByRole('img')).toBeTruthy();
@@ -0,0 +1,2 @@
1
+ declare const rehypeHighlight: () => (tree: any) => any;
2
+ export default rehypeHighlight;
@@ -0,0 +1,2 @@
1
+ const rehypeHighlight = () => (tree) => tree;
2
+ export default rehypeHighlight;
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/SourcesCardBase/SourcesCardBase.test.tsx","../src/SourcesCardBase/SourcesCardBase.tsx","../src/SourcesCardBase/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolCall/ToolCall.test.tsx","../src/ToolCall/ToolCall.tsx","../src/ToolCall/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
1
+ {"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderNewChatButton.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/DeepThinking/DeepThinking.test.tsx","../src/DeepThinking/DeepThinking.tsx","../src/DeepThinking/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/FilePreview/FilePreview.test.tsx","../src/FilePreview/FilePreview.tsx","../src/FilePreview/index.ts","../src/ImagePreview/ImagePreview.test.tsx","../src/ImagePreview/ImagePreview.tsx","../src/ImagePreview/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/index.ts","../src/Message/Plugins/rehypeCodeBlockToggle.ts","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/SuperscriptMessage/SuperscriptMessage.tsx","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/MessageDivider/MessageDivider.test.tsx","../src/MessageDivider/MessageDivider.tsx","../src/MessageDivider/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/SourcesCardBase/SourcesCardBase.test.tsx","../src/SourcesCardBase/SourcesCardBase.tsx","../src/SourcesCardBase/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/ToolCall/ToolCall.test.tsx","../src/ToolCall/ToolCall.tsx","../src/ToolCall/index.ts","../src/ToolResponse/ToolResponse.test.tsx","../src/ToolResponse/ToolResponse.tsx","../src/ToolResponse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-highlight.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "6.5.0-prerelease.1",
3
+ "version": "6.5.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",
@@ -43,6 +43,7 @@
43
43
  "posthog-js": "^1.194.4",
44
44
  "react-markdown": "^9.0.1",
45
45
  "rehype-external-links": "^3.0.0",
46
+ "rehype-highlight": "^7.0.0",
46
47
  "rehype-sanitize": "^6.0.0",
47
48
  "rehype-unwrap-images": "^1.0.0",
48
49
  "remark-gfm": "^4.0.0",
@@ -5,8 +5,8 @@ import ChatbotConversationHistoryNav, {
5
5
  } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
6
6
  import { Checkbox, DropdownItem, DropdownList } from '@patternfly/react-core';
7
7
 
8
- const menuItems = [
9
- <DropdownList key="list-1">
8
+ const generateMenuItems = (id: string) => [
9
+ <DropdownList key={`header-drawer-with-actions-example-conversation-${id}-dropdown`}>
10
10
  <DropdownItem value="Download" id="Download">
11
11
  Download
12
12
  </DropdownItem>
@@ -23,29 +23,29 @@ const menuItems = [
23
23
  ];
24
24
 
25
25
  const conversations: { [key: string]: Conversation[] } = {
26
- Today: [{ id: '1', text: 'Red Hat products and services', menuItems }],
26
+ Today: [{ id: '1', text: 'Red Hat products and services', menuItems: generateMenuItems('1') }],
27
27
  'This month': [
28
28
  {
29
29
  id: '2',
30
30
  text: 'Enterprise Linux installation and setup',
31
- menuItems
31
+ menuItems: generateMenuItems('2')
32
32
  },
33
- { id: '3', text: 'Troubleshoot system crash', menuItems }
33
+ { id: '3', text: 'Troubleshoot system crash', menuItems: generateMenuItems('3') }
34
34
  ],
35
35
  March: [
36
- { id: '4', text: 'Ansible security and updates', menuItems },
37
- { id: '5', text: 'Red Hat certification', menuItems },
38
- { id: '6', text: 'Lightspeed user documentation', menuItems }
36
+ { id: '4', text: 'Ansible security and updates', menuItems: generateMenuItems('4') },
37
+ { id: '5', text: 'Red Hat certification', menuItems: generateMenuItems('5') },
38
+ { id: '6', text: 'Lightspeed user documentation', menuItems: generateMenuItems('6') }
39
39
  ],
40
40
  February: [
41
- { id: '7', text: 'Crashing pod assistance', menuItems },
42
- { id: '8', text: 'OpenShift AI pipelines', menuItems },
43
- { id: '9', text: 'Updating subscription plan', menuItems },
44
- { id: '10', text: 'Red Hat licensing options', menuItems }
41
+ { id: '7', text: 'Crashing pod assistance', menuItems: generateMenuItems('7') },
42
+ { id: '8', text: 'OpenShift AI pipelines', menuItems: generateMenuItems('8') },
43
+ { id: '9', text: 'Updating subscription plan', menuItems: generateMenuItems('9') },
44
+ { id: '10', text: 'Red Hat licensing options', menuItems: generateMenuItems('10') }
45
45
  ],
46
46
  January: [
47
- { id: '11', text: 'RHEL system performance', menuItems },
48
- { id: '12', text: 'Manage user accounts', menuItems }
47
+ { id: '11', text: 'RHEL system performance', menuItems: generateMenuItems('11') },
48
+ { id: '12', text: 'Manage user accounts', menuItems: generateMenuItems('12') }
49
49
  ]
50
50
  };
51
51
 
@@ -5,8 +5,8 @@ import ChatbotConversationHistoryNav, {
5
5
  } from '@patternfly/chatbot/dist/dynamic/ChatbotConversationHistoryNav';
6
6
  import { Checkbox, DropdownItem, DropdownList } from '@patternfly/react-core';
7
7
 
8
- const menuItems = [
9
- <DropdownList key="list-1">
8
+ const generateMenuItems = (id: string) => [
9
+ <DropdownList key={`header-drawer-with-selections-example-conversation-${id}-dropdown`}>
10
10
  <DropdownItem value="Download" id="Download">
11
11
  Download
12
12
  </DropdownItem>
@@ -29,29 +29,29 @@ export const ChatbotHeaderDrawerWithSelection: FunctionComponent = () => {
29
29
  const displayMode = ChatbotDisplayMode.embedded;
30
30
 
31
31
  const conversations: { [key: string]: Conversation[] } = {
32
- Today: [{ id: '1', text: 'Red Hat products and services', menuItems }],
32
+ Today: [{ id: '1', text: 'Red Hat products and services', menuItems: generateMenuItems('1') }],
33
33
  'This month': [
34
34
  {
35
35
  id: '2',
36
36
  text: 'Enterprise Linux installation and setup',
37
- menuItems
37
+ menuItems: generateMenuItems('2')
38
38
  },
39
- { id: '3', text: 'Troubleshoot system crash', menuItems }
39
+ { id: '3', text: 'Troubleshoot system crash', menuItems: generateMenuItems('3') }
40
40
  ],
41
41
  March: [
42
- { id: '4', text: 'Ansible security and updates', menuItems },
43
- { id: '5', text: 'Red Hat certification', menuItems },
44
- { id: '6', text: 'Lightspeed user documentation', menuItems }
42
+ { id: '4', text: 'Ansible security and updates', menuItems: generateMenuItems('4') },
43
+ { id: '5', text: 'Red Hat certification', menuItems: generateMenuItems('5') },
44
+ { id: '6', text: 'Lightspeed user documentation', menuItems: generateMenuItems('6') }
45
45
  ],
46
46
  February: [
47
- { id: '7', text: 'Crashing pod assistance', menuItems },
48
- { id: '8', text: 'OpenShift AI pipelines', menuItems },
49
- { id: '9', text: 'Updating subscription plan', menuItems },
50
- { id: '10', text: 'Red Hat licensing options', menuItems }
47
+ { id: '7', text: 'Crashing pod assistance', menuItems: generateMenuItems('7') },
48
+ { id: '8', text: 'OpenShift AI pipelines', menuItems: generateMenuItems('8') },
49
+ { id: '9', text: 'Updating subscription plan', menuItems: generateMenuItems('9') },
50
+ { id: '10', text: 'Red Hat licensing options', menuItems: generateMenuItems('10') }
51
51
  ],
52
52
  January: [
53
- { id: '11', text: 'RHEL system performance', menuItems },
54
- { id: '12', text: 'Manage user accounts', menuItems }
53
+ { id: '11', text: 'RHEL system performance', menuItems: generateMenuItems('11') },
54
+ { id: '12', text: 'Manage user accounts', menuItems: generateMenuItems('12') }
55
55
  ]
56
56
  };
57
57
 
@@ -66,7 +66,7 @@ export const ChatbotMessageBarDefaultAttachExample: FunctionComponent = () => {
66
66
  };
67
67
 
68
68
  const initialMenuItems = [
69
- <DropdownList key="list-1">
69
+ <DropdownList key="message-bar-attach-menu-items">
70
70
  <DropdownItem className="pf-chatbot-source-details-dropdown-item" value="auth-operator Pod" id="0">
71
71
  <SourceDetailsMenuItem
72
72
  icon={
@@ -93,7 +93,7 @@ export const ChatbotMessageBarDefaultAttachExample: FunctionComponent = () => {
93
93
  />
94
94
  </DropdownItem>
95
95
  </DropdownList>,
96
- <DropdownGroup key="group2">
96
+ <DropdownGroup key="message-bar-attach-dropdown-group">
97
97
  <DropdownList>
98
98
  <DropdownItem value="Alerts" id="1" icon={<BellIcon />}>
99
99
  Alerts
@@ -20,7 +20,7 @@ import '@patternfly/chatbot/dist/css/main.css';
20
20
  import { cloneElement, FunctionComponent, isValidElement, ReactNode, useState, Children } from 'react';
21
21
 
22
22
  const initialMenuItems = [
23
- <DropdownList key="list-1">
23
+ <DropdownList key="attachment-menu-example-initial-menu-items">
24
24
  <DropdownItem value="auth-operator Pod" id="0" className="pf-chatbot-source-details-dropdown-item">
25
25
  <SourceDetailsMenuItem
26
26
  icon={
@@ -47,7 +47,7 @@ const initialMenuItems = [
47
47
  />
48
48
  </DropdownItem>
49
49
  </DropdownList>,
50
- <DropdownGroup key="group2">
50
+ <DropdownGroup key="attachment-menu-example-initial-group">
51
51
  <DropdownList>
52
52
  <DropdownItem value="Alerts" id="1" icon={<BellIcon />}>
53
53
  Alerts
@@ -230,7 +230,7 @@ export const ChatbotDemo: FunctionComponent = () => {
230
230
  id: '1',
231
231
  text: 'Hello, can you give me an example of what you can do?',
232
232
  menuItems: (
233
- <DropdownList key={`list-1`}>
233
+ <DropdownList key="transcript-example-initial-menu-items">
234
234
  <DropdownItem
235
235
  value="Download"
236
236
  id={`Download-1`}
@@ -4,5 +4,6 @@ module.exports = {
4
4
  topNavItems: [],
5
5
  hasThemeSwitcher: true,
6
6
  hasRTLSwitcher: true,
7
+ hasHighContrastSwitcher: true,
7
8
  port: 8006
8
9
  };
@@ -12,6 +12,10 @@
12
12
  @media screen and (max-height: 518px) {
13
13
  overflow: unset;
14
14
  }
15
+
16
+ &.pf-m-primary {
17
+ background-color: var(--pf-t--global--background--color--primary--default);
18
+ }
15
19
  }
16
20
 
17
21
  // ============================================================================
@@ -11,4 +11,9 @@ describe('ChatbotContent', () => {
11
11
  const { container } = render(<ChatbotContent className="custom-class">Chatbot Content</ChatbotContent>);
12
12
  expect(container.querySelector('.custom-class')).toBeTruthy();
13
13
  });
14
+
15
+ it('should render ChatbotContent with primary class', () => {
16
+ const { container } = render(<ChatbotContent isPrimary>Chatbot Content</ChatbotContent>);
17
+ expect(container.querySelector('.pf-m-primary')).toBeTruthy();
18
+ });
14
19
  });
@@ -8,14 +8,17 @@ export interface ChatbotContentProps extends HTMLProps<HTMLDivElement> {
8
8
  children: React.ReactNode;
9
9
  /** Custom classname for the ChatbotContent component */
10
10
  className?: string;
11
+ /** Sets background color to primary */
12
+ isPrimary?: boolean;
11
13
  }
12
14
 
13
15
  export const ChatbotContent: FunctionComponent<ChatbotContentProps> = ({
14
16
  children,
15
17
  className,
18
+ isPrimary,
16
19
  ...props
17
20
  }: ChatbotContentProps) => (
18
- <div className={`pf-chatbot__content ${className ?? ''}`} {...props}>
21
+ <div className={`pf-chatbot__content ${isPrimary ? 'pf-m-primary' : ''} ${className ?? ''}`} {...props}>
19
22
  {children}
20
23
  </div>
21
24
  );
@@ -78,4 +78,9 @@ describe('ChatbotConversationHistoryDropdown', () => {
78
78
  expect(screen.queryByText('Actions dropdown')).toBeInTheDocument();
79
79
  });
80
80
  });
81
+
82
+ it('should be able to set a custom aria-label', () => {
83
+ render(<ChatbotConversationHistoryDropdown menuItems={menuItems} aria-label="Custom conversation options" />);
84
+ expect(screen.queryByRole('menuitem', { name: /Custom conversation options/i })).toBeInTheDocument();
85
+ });
81
86
  });
@@ -15,8 +15,10 @@ export interface ChatbotConversationHistoryDropdownProps extends Omit<DropdownPr
15
15
  menuItems: React.ReactNode;
16
16
  /** Optional classname applied to conversation settings dropdown */
17
17
  menuClassName?: string;
18
- /** Tooltip content and aria-label applied to conversation settings dropdown */
18
+ /** Tooltip content applied to conversation settings dropdown */
19
19
  label?: string;
20
+ /** Aria-label applied to conversation settings dropdown */
21
+ 'aria-label'?: string;
20
22
  /** Callback for when user selects item. */
21
23
  onSelect?: (event?: React.MouseEvent, value?: string | number) => void;
22
24
  /** Id applied to dropdown menu toggle */
@@ -27,7 +29,8 @@ export const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConver
27
29
  menuItems,
28
30
  menuClassName,
29
31
  onSelect,
30
- label,
32
+ label = 'Conversation options',
33
+ 'aria-label': ariaLabel,
31
34
  id
32
35
  }: ChatbotConversationHistoryDropdownProps) => {
33
36
  const [isOpen, setIsOpen] = useState(false);
@@ -35,7 +38,7 @@ export const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConver
35
38
  const toggle = (toggleRef: Ref<MenuToggleElement>) => (
36
39
  <Tooltip
37
40
  className="pf-chatbot__tooltip"
38
- content={label ?? 'Conversation options'}
41
+ content={label}
39
42
  position="bottom"
40
43
  // prevents VO announcements of both aria label and tooltip
41
44
  aria="none"
@@ -43,7 +46,7 @@ export const ChatbotConversationHistoryDropdown: FunctionComponent<ChatbotConver
43
46
  <MenuToggle
44
47
  className="pf-chatbot__history-actions"
45
48
  variant="plain"
46
- aria-label={label ?? 'Conversation options'}
49
+ aria-label={ariaLabel ?? label}
47
50
  ref={toggleRef}
48
51
  isExpanded={isOpen}
49
52
  onClick={() => setIsOpen(!isOpen)}
@@ -1,13 +1,23 @@
1
1
  // ============================================================================
2
2
  // Code Modal - Chatbot Modal with Code Editor
3
3
  // ============================================================================
4
+
4
5
  import type { FunctionComponent, MouseEvent } from 'react';
5
- import { useState } from 'react';
6
+ import { useState, useEffect, useRef } from 'react';
6
7
  import path from 'path-browserify';
8
+ import type monaco from 'monaco-editor';
7
9
 
8
10
  // Import PatternFly components
9
11
  import { CodeEditor } from '@patternfly/react-code-editor';
10
- import { Button, ModalBody, ModalFooter, ModalHeader, Stack, StackItem } from '@patternfly/react-core';
12
+ import {
13
+ Button,
14
+ getResizeObserver,
15
+ ModalBody,
16
+ ModalFooter,
17
+ ModalHeader,
18
+ Stack,
19
+ StackItem
20
+ } from '@patternfly/react-core';
11
21
  import FileDetails, { extensionToLanguage } from '../FileDetails';
12
22
  import { ChatbotDisplayMode } from '../Chatbot';
13
23
  import ChatbotModal from '../ChatbotModal/ChatbotModal';
@@ -73,6 +83,34 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
73
83
  ...props
74
84
  }: CodeModalProps) => {
75
85
  const [newCode, setNewCode] = useState(code);
86
+ const [editorInstance, setEditorInstance] = useState<monaco.editor.IStandaloneCodeEditor | null>(null);
87
+ const [isEditorReady, setIsEditorReady] = useState(false);
88
+ const containerRef = useRef<HTMLDivElement>(null);
89
+
90
+ useEffect(() => {
91
+ if (!isModalOpen || !isEditorReady || !editorInstance || !containerRef.current) {
92
+ return;
93
+ }
94
+
95
+ const handleResize = () => {
96
+ if (editorInstance && isEditorReady && isModalOpen) {
97
+ try {
98
+ window.requestAnimationFrame(() => {
99
+ editorInstance.layout();
100
+ });
101
+ } catch (error) {
102
+ // eslint-disable-next-line no-console
103
+ console.error('ChatBot code modal layout error:', error);
104
+ }
105
+ }
106
+ };
107
+
108
+ const observer = getResizeObserver(containerRef.current, handleResize);
109
+
110
+ return () => {
111
+ observer();
112
+ };
113
+ }, [editorInstance, isEditorReady, isModalOpen]);
76
114
 
77
115
  const handlePrimaryAction = (_event: MouseEvent | MouseEvent | KeyboardEvent) => {
78
116
  handleModalToggle(_event);
@@ -89,9 +127,15 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
89
127
  };
90
128
 
91
129
  const onEditorDidMount = (editor, monaco) => {
92
- editor.layout();
93
- editor.focus();
130
+ setEditorInstance(editor);
131
+
94
132
  monaco.editor.getModels()[0].updateOptions({ tabSize: 5 });
133
+
134
+ if (containerRef.current) {
135
+ setIsEditorReady(true);
136
+ editor.layout();
137
+ editor.focus();
138
+ }
95
139
  };
96
140
 
97
141
  const onCodeChange = (value: string) => {
@@ -117,7 +161,7 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
117
161
  <StackItem className="pf-chatbot__code-modal-file-details">
118
162
  <FileDetails fileName={fileName} />
119
163
  </StackItem>
120
- <StackItem className="pf-chatbot__code-modal-editor">
164
+ <div className="pf-v6-l-stack__item pf-chatbot__code-modal-editor" ref={containerRef}>
121
165
  <CodeEditor
122
166
  isDarkTheme
123
167
  isLineNumbersVisible={isLineNumbersVisible}
@@ -132,11 +176,14 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
132
176
  isFullHeight
133
177
  options={{
134
178
  glyphMargin: false,
135
- folding: false
179
+ folding: false,
180
+ // prevents Monaco from handling resizing itself
181
+ // was causing ResizeObserver issues
182
+ automaticLayout: false
136
183
  }}
137
184
  {...props}
138
185
  />
139
- </StackItem>
186
+ </div>
140
187
  </Stack>
141
188
  </ModalBody>
142
189
  <ModalFooter className={modalFooterClassName}>
@@ -30,7 +30,8 @@
30
30
  font-family: var(--pf-t--global--font--family--body);
31
31
  }
32
32
 
33
- .pf-v6-c-code-block__actions-item {
33
+ // we are overriding some default PatternFly positioning here - it's only necessary for the first two items
34
+ .pf-chatbot__message-code-block-default-action {
34
35
  display: flex;
35
36
  align-items: center;
36
37
  justify-content: space-between;
@@ -39,7 +40,7 @@
39
40
  font-weight: var(--pf-t--global--font--weight--body--bold);
40
41
  }
41
42
 
42
- .pf-chatbot__button--copy.pf-v6-c-button {
43
+ .pf-v6-c-code-block__actions-item > .pf-v6-c-button.pf-m-plain {
43
44
  color: var(--pf-t--color--white); // same in light + dark theme
44
45
 
45
46
  &:hover,
@@ -37,6 +37,8 @@ export interface CodeBlockMessageProps {
37
37
  expandedText?: string;
38
38
  /** Link text applied to expandable toggle when collapsed */
39
39
  collapsedText?: string;
40
+ /** Custom actions added to header of code block, after any default actions such as the "copy" action. */
41
+ customActions?: React.ReactNode;
40
42
  }
41
43
 
42
44
  const DEFAULT_EXPANDED_TEXT = 'Show less';
@@ -51,6 +53,7 @@ const CodeBlockMessage = ({
51
53
  expandableSectionToggleProps,
52
54
  expandedText = DEFAULT_EXPANDED_TEXT,
53
55
  collapsedText = DEFAULT_COLLAPSED_TEXT,
56
+ customActions,
54
57
  ...props
55
58
  }: CodeBlockMessageProps) => {
56
59
  const [copied, setCopied] = useState(false);
@@ -114,7 +117,7 @@ const CodeBlockMessage = ({
114
117
  // Setup code block header
115
118
  const actions = (
116
119
  <>
117
- <CodeBlockAction>
120
+ <CodeBlockAction className="pf-chatbot__message-code-block-default-action">
118
121
  {language && <div className="pf-chatbot__message-code-block-language">{language}</div>}
119
122
  <Button
120
123
  ref={buttonRef}
@@ -127,6 +130,7 @@ const CodeBlockMessage = ({
127
130
  </Button>
128
131
  <Tooltip id={tooltipID} content="Copy" position="top" triggerRef={buttonRef} />
129
132
  </CodeBlockAction>
133
+ {customActions}
130
134
  </>
131
135
  );
132
136
 
@@ -6,7 +6,7 @@ import userEvent from '@testing-library/user-event';
6
6
  import { monitorSampleAppQuickStart } from './QuickStarts/monitor-sampleapp-quickstart';
7
7
  import { monitorSampleAppQuickStartWithImage } from './QuickStarts/monitor-sampleapp-quickstart-with-image';
8
8
  import rehypeExternalLinks from '../__mocks__/rehype-external-links';
9
- import { AlertActionLink } from '@patternfly/react-core';
9
+ import { AlertActionLink, Button, CodeBlockAction } from '@patternfly/react-core';
10
10
  import { DeepThinkingProps } from '../DeepThinking';
11
11
 
12
12
  const ALL_ACTIONS = [
@@ -612,6 +612,24 @@ describe('Message', () => {
612
612
  );
613
613
  expect(screen.getByRole('button', { name: 'test' })).toBeTruthy();
614
614
  });
615
+ it('should be able to add custom actions to CodeMessage', () => {
616
+ render(
617
+ <Message
618
+ avatar="./img"
619
+ role="user"
620
+ name="User"
621
+ content={CODE_MESSAGE}
622
+ codeBlockProps={{
623
+ customActions: (
624
+ <CodeBlockAction>
625
+ <Button>New custom action</Button>
626
+ </CodeBlockAction>
627
+ )
628
+ }}
629
+ />
630
+ );
631
+ expect(screen.getByRole('button', { name: /New custom action/i })).toBeTruthy();
632
+ });
615
633
  it('should handle hasRoundAvatar correctly when it is true', () => {
616
634
  render(<Message avatar="./img" role="user" name="User" content="Hi" hasRoundAvatar />);
617
635
  expect(screen.getByRole('img')).toBeTruthy();