@patternfly/chatbot 6.5.0-prerelease.3 → 6.5.0-prerelease.30
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.
- package/dist/cjs/AttachMenu/AttachMenu.d.ts +8 -2
- package/dist/cjs/AttachMenu/AttachMenu.js +2 -2
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +9 -1
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +9 -2
- package/dist/cjs/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +38 -0
- package/dist/cjs/ChatbotFooter/ChatbotFooter.d.ts +5 -2
- package/dist/cjs/ChatbotFooter/ChatbotFooter.js +2 -2
- package/dist/cjs/ChatbotFooter/ChatbotFooter.test.js +5 -1
- package/dist/cjs/ChatbotHeader/ChatbotHeaderMenu.js +29 -2
- package/dist/cjs/CodeModal/CodeModal.d.ts +2 -0
- package/dist/cjs/CodeModal/CodeModal.js +53 -8
- package/dist/cjs/DeepThinking/DeepThinking.d.ts +13 -0
- package/dist/cjs/DeepThinking/DeepThinking.js +31 -3
- package/dist/cjs/DeepThinking/DeepThinking.test.js +80 -0
- package/dist/cjs/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
- package/dist/cjs/MarkdownContent/MarkdownContent.d.ts +44 -0
- package/dist/cjs/MarkdownContent/MarkdownContent.js +181 -0
- package/dist/cjs/MarkdownContent/MarkdownContent.test.d.ts +1 -0
- package/dist/cjs/MarkdownContent/MarkdownContent.test.js +192 -0
- package/dist/cjs/MarkdownContent/index.d.ts +2 -0
- package/dist/cjs/MarkdownContent/index.js +23 -0
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +16 -5
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.test.d.ts +1 -0
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.test.js +131 -0
- package/dist/cjs/Message/ErrorMessage/ErrorMessage.d.ts +15 -1
- package/dist/cjs/Message/ErrorMessage/ErrorMessage.js +5 -3
- package/dist/cjs/Message/ErrorMessage/ErrorMessage.test.d.ts +1 -0
- package/dist/cjs/Message/ErrorMessage/ErrorMessage.test.js +30 -0
- package/dist/cjs/Message/LinkMessage/LinkMessage.d.ts +5 -1
- package/dist/cjs/Message/LinkMessage/LinkMessage.js +4 -3
- package/dist/cjs/Message/ListMessage/OrderedListMessage.d.ts +9 -1
- package/dist/cjs/Message/ListMessage/OrderedListMessage.js +2 -1
- package/dist/cjs/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
- package/dist/cjs/Message/ListMessage/UnorderedListMessage.js +2 -1
- package/dist/cjs/Message/Message.d.ts +22 -3
- package/dist/cjs/Message/Message.js +8 -161
- package/dist/cjs/Message/Message.test.js +161 -2
- package/dist/cjs/Message/MessageAndActions/MessageAndActions.d.ts +14 -0
- package/dist/cjs/Message/MessageAndActions/MessageAndActions.js +22 -0
- package/dist/cjs/Message/MessageAndActions/MessageAndActions.test.d.ts +1 -0
- package/dist/cjs/Message/MessageAndActions/MessageAndActions.test.js +25 -0
- package/dist/cjs/Message/MessageAndActions/index.d.ts +1 -0
- package/dist/cjs/Message/MessageAndActions/index.js +17 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.d.ts +13 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.js +22 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.test.d.ts +1 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentItem.test.js +25 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.d.ts +13 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.js +22 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.test.d.ts +1 -0
- package/dist/cjs/Message/MessageAttachments/MessageAttachmentsContainer.test.js +25 -0
- package/dist/cjs/Message/MessageAttachments/index.d.ts +2 -0
- package/dist/cjs/Message/MessageAttachments/index.js +18 -0
- package/dist/cjs/Message/MessageInput.d.ts +1 -1
- package/dist/cjs/Message/MessageInput.js +3 -1
- package/dist/cjs/Message/MessageLoading.d.ts +13 -3
- package/dist/cjs/Message/MessageLoading.js +19 -5
- package/dist/cjs/Message/MessageLoading.test.d.ts +1 -0
- package/dist/cjs/Message/MessageLoading.test.js +25 -0
- package/dist/cjs/Message/QuickResponse/QuickResponse.js +3 -2
- package/dist/cjs/Message/QuickResponse/QuickResponse.test.d.ts +1 -0
- package/dist/cjs/Message/QuickResponse/QuickResponse.test.js +109 -0
- package/dist/cjs/Message/QuickResponse/index.d.ts +1 -0
- package/dist/cjs/Message/QuickResponse/index.js +17 -0
- package/dist/cjs/Message/QuickStarts/QuickStartTile.d.ts +1 -1
- package/dist/cjs/Message/QuickStarts/QuickStartTile.js +3 -2
- package/dist/cjs/Message/QuickStarts/index.d.ts +2 -0
- package/dist/cjs/Message/QuickStarts/index.js +18 -0
- package/dist/cjs/Message/TableMessage/TableMessage.d.ts +9 -1
- package/dist/cjs/Message/TableMessage/TableMessage.js +3 -2
- package/dist/cjs/Message/TextMessage/TextMessage.d.ts +11 -1
- package/dist/cjs/Message/TextMessage/TextMessage.js +3 -2
- package/dist/cjs/Message/UserFeedback/UserFeedback.d.ts +3 -1
- package/dist/cjs/Message/UserFeedback/UserFeedback.js +8 -6
- package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.d.ts +1 -1
- package/dist/cjs/Message/UserFeedback/UserFeedbackComplete.js +3 -2
- package/dist/cjs/Message/UserFeedback/index.d.ts +2 -0
- package/dist/cjs/Message/UserFeedback/index.js +18 -0
- package/dist/cjs/Message/index.d.ts +8 -0
- package/dist/cjs/Message/index.js +8 -0
- package/dist/cjs/MessageBar/AttachButton.d.ts +2 -0
- package/dist/cjs/MessageBar/AttachButton.js +2 -2
- package/dist/cjs/MessageBar/AttachButton.test.js +4 -0
- package/dist/cjs/MessageBar/MessageBar.d.ts +22 -6
- package/dist/cjs/MessageBar/MessageBar.js +43 -11
- package/dist/cjs/MessageBar/MessageBar.test.js +74 -0
- package/dist/cjs/Onboarding/Onboarding.d.ts +36 -0
- package/dist/cjs/Onboarding/Onboarding.js +37 -0
- package/dist/cjs/Onboarding/Onboarding.test.d.ts +1 -0
- package/dist/cjs/Onboarding/Onboarding.test.js +80 -0
- package/dist/cjs/Onboarding/index.d.ts +2 -0
- package/dist/cjs/Onboarding/index.js +23 -0
- package/dist/cjs/ResponseActions/ResponseActions.d.ts +7 -0
- package/dist/cjs/ResponseActions/ResponseActions.js +28 -7
- package/dist/cjs/ResponseActions/ResponseActions.test.js +67 -12
- package/dist/cjs/ResponseActions/ResponseActionsGroups.d.ts +13 -0
- package/dist/cjs/ResponseActions/ResponseActionsGroups.js +22 -0
- package/dist/cjs/ResponseActions/ResponseActionsGroups.test.d.ts +1 -0
- package/dist/cjs/ResponseActions/ResponseActionsGroups.test.js +25 -0
- package/dist/cjs/ResponseActions/index.d.ts +1 -0
- package/dist/cjs/ResponseActions/index.js +1 -0
- package/dist/cjs/ToolCall/ToolCall.d.ts +11 -0
- package/dist/cjs/ToolCall/ToolCall.js +24 -3
- package/dist/cjs/ToolCall/ToolCall.test.js +57 -0
- package/dist/cjs/ToolResponse/ToolResponse.d.ts +17 -0
- package/dist/cjs/ToolResponse/ToolResponse.js +49 -3
- package/dist/cjs/ToolResponse/ToolResponse.test.js +100 -0
- package/dist/cjs/__mocks__/monaco-editor.d.ts +11 -0
- package/dist/cjs/__mocks__/monaco-editor.js +18 -0
- package/dist/cjs/index.d.ts +4 -0
- package/dist/cjs/index.js +7 -1
- package/dist/css/main.css +336 -30
- package/dist/css/main.css.map +1 -1
- package/dist/dynamic/MarkdownContent/package.json +1 -0
- package/dist/dynamic/Onboarding/package.json +1 -0
- package/dist/esm/AttachMenu/AttachMenu.d.ts +8 -2
- package/dist/esm/AttachMenu/AttachMenu.js +2 -2
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.d.ts +9 -1
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.js +10 -3
- package/dist/esm/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.js +38 -0
- package/dist/esm/ChatbotFooter/ChatbotFooter.d.ts +5 -2
- package/dist/esm/ChatbotFooter/ChatbotFooter.js +2 -2
- package/dist/esm/ChatbotFooter/ChatbotFooter.test.js +5 -1
- package/dist/esm/ChatbotHeader/ChatbotHeaderMenu.js +30 -3
- package/dist/esm/CodeModal/CodeModal.d.ts +2 -0
- package/dist/esm/CodeModal/CodeModal.js +54 -9
- package/dist/esm/DeepThinking/DeepThinking.d.ts +13 -0
- package/dist/esm/DeepThinking/DeepThinking.js +28 -3
- package/dist/esm/DeepThinking/DeepThinking.test.js +80 -0
- package/dist/esm/FileDetailsLabel/FileDetailsLabel.d.ts +2 -1
- package/dist/esm/MarkdownContent/MarkdownContent.d.ts +44 -0
- package/dist/esm/MarkdownContent/MarkdownContent.js +174 -0
- package/dist/esm/MarkdownContent/MarkdownContent.test.d.ts +1 -0
- package/dist/esm/MarkdownContent/MarkdownContent.test.js +187 -0
- package/dist/esm/MarkdownContent/index.d.ts +2 -0
- package/dist/esm/MarkdownContent/index.js +2 -0
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +5 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +16 -5
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.test.d.ts +1 -0
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.test.js +126 -0
- package/dist/esm/Message/ErrorMessage/ErrorMessage.d.ts +15 -1
- package/dist/esm/Message/ErrorMessage/ErrorMessage.js +3 -3
- package/dist/esm/Message/ErrorMessage/ErrorMessage.test.d.ts +1 -0
- package/dist/esm/Message/ErrorMessage/ErrorMessage.test.js +25 -0
- package/dist/esm/Message/LinkMessage/LinkMessage.d.ts +5 -1
- package/dist/esm/Message/LinkMessage/LinkMessage.js +4 -3
- package/dist/esm/Message/ListMessage/OrderedListMessage.d.ts +9 -1
- package/dist/esm/Message/ListMessage/OrderedListMessage.js +2 -1
- package/dist/esm/Message/ListMessage/UnorderedListMessage.d.ts +7 -1
- package/dist/esm/Message/ListMessage/UnorderedListMessage.js +2 -1
- package/dist/esm/Message/Message.d.ts +22 -3
- package/dist/esm/Message/Message.js +9 -162
- package/dist/esm/Message/Message.test.js +161 -2
- package/dist/esm/Message/MessageAndActions/MessageAndActions.d.ts +14 -0
- package/dist/esm/Message/MessageAndActions/MessageAndActions.js +18 -0
- package/dist/esm/Message/MessageAndActions/MessageAndActions.test.d.ts +1 -0
- package/dist/esm/Message/MessageAndActions/MessageAndActions.test.js +20 -0
- package/dist/esm/Message/MessageAndActions/index.d.ts +1 -0
- package/dist/esm/Message/MessageAndActions/index.js +1 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.d.ts +13 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.js +18 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.test.d.ts +1 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentItem.test.js +20 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.d.ts +13 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.js +18 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.test.d.ts +1 -0
- package/dist/esm/Message/MessageAttachments/MessageAttachmentsContainer.test.js +20 -0
- package/dist/esm/Message/MessageAttachments/index.d.ts +2 -0
- package/dist/esm/Message/MessageAttachments/index.js +2 -0
- package/dist/esm/Message/MessageInput.d.ts +1 -1
- package/dist/esm/Message/MessageInput.js +1 -1
- package/dist/esm/Message/MessageLoading.d.ts +13 -3
- package/dist/esm/Message/MessageLoading.js +16 -4
- package/dist/esm/Message/MessageLoading.test.d.ts +1 -0
- package/dist/esm/Message/MessageLoading.test.js +20 -0
- package/dist/esm/Message/QuickResponse/QuickResponse.js +3 -2
- package/dist/esm/Message/QuickResponse/QuickResponse.test.d.ts +1 -0
- package/dist/esm/Message/QuickResponse/QuickResponse.test.js +104 -0
- package/dist/esm/Message/QuickResponse/index.d.ts +1 -0
- package/dist/esm/Message/QuickResponse/index.js +1 -0
- package/dist/esm/Message/QuickStarts/QuickStartTile.d.ts +1 -1
- package/dist/esm/Message/QuickStarts/QuickStartTile.js +1 -1
- package/dist/esm/Message/QuickStarts/index.d.ts +2 -0
- package/dist/esm/Message/QuickStarts/index.js +2 -0
- package/dist/esm/Message/TableMessage/TableMessage.d.ts +9 -1
- package/dist/esm/Message/TableMessage/TableMessage.js +3 -2
- package/dist/esm/Message/TextMessage/TextMessage.d.ts +11 -1
- package/dist/esm/Message/TextMessage/TextMessage.js +3 -2
- package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +3 -1
- package/dist/esm/Message/UserFeedback/UserFeedback.js +7 -7
- package/dist/esm/Message/UserFeedback/UserFeedbackComplete.d.ts +1 -1
- package/dist/esm/Message/UserFeedback/UserFeedbackComplete.js +1 -2
- package/dist/esm/Message/UserFeedback/index.d.ts +2 -0
- package/dist/esm/Message/UserFeedback/index.js +2 -0
- package/dist/esm/Message/index.d.ts +8 -0
- package/dist/esm/Message/index.js +8 -0
- package/dist/esm/MessageBar/AttachButton.d.ts +2 -0
- package/dist/esm/MessageBar/AttachButton.js +2 -2
- package/dist/esm/MessageBar/AttachButton.test.js +4 -0
- package/dist/esm/MessageBar/MessageBar.d.ts +22 -6
- package/dist/esm/MessageBar/MessageBar.js +43 -11
- package/dist/esm/MessageBar/MessageBar.test.js +74 -0
- package/dist/esm/Onboarding/Onboarding.d.ts +36 -0
- package/dist/esm/Onboarding/Onboarding.js +30 -0
- package/dist/esm/Onboarding/Onboarding.test.d.ts +1 -0
- package/dist/esm/Onboarding/Onboarding.test.js +75 -0
- package/dist/esm/Onboarding/index.d.ts +2 -0
- package/dist/esm/Onboarding/index.js +2 -0
- package/dist/esm/ResponseActions/ResponseActions.d.ts +7 -0
- package/dist/esm/ResponseActions/ResponseActions.js +28 -7
- package/dist/esm/ResponseActions/ResponseActions.test.js +67 -12
- package/dist/esm/ResponseActions/ResponseActionsGroups.d.ts +13 -0
- package/dist/esm/ResponseActions/ResponseActionsGroups.js +18 -0
- package/dist/esm/ResponseActions/ResponseActionsGroups.test.d.ts +1 -0
- package/dist/esm/ResponseActions/ResponseActionsGroups.test.js +20 -0
- package/dist/esm/ResponseActions/index.d.ts +1 -0
- package/dist/esm/ResponseActions/index.js +1 -0
- package/dist/esm/ToolCall/ToolCall.d.ts +11 -0
- package/dist/esm/ToolCall/ToolCall.js +21 -3
- package/dist/esm/ToolCall/ToolCall.test.js +57 -0
- package/dist/esm/ToolResponse/ToolResponse.d.ts +17 -0
- package/dist/esm/ToolResponse/ToolResponse.js +46 -3
- package/dist/esm/ToolResponse/ToolResponse.test.js +100 -0
- package/dist/esm/__mocks__/monaco-editor.d.ts +11 -0
- package/dist/esm/__mocks__/monaco-editor.js +18 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -2
- package/patternfly-docs/content/extensions/chatbot/chatbot.md +57 -0
- package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +12 -12
- package/patternfly-docs/content/extensions/chatbot/examples/Analytics/Analytics.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Customizing Messages/Customizing Messages.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +1 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithCustomStructure.tsx +102 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +25 -11
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +14 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownDeepThinking.tsx +26 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolCall.tsx +29 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMarkdownToolResponse.tsx +200 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithMultipleActionGroups.tsx +61 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithPersistedActions.tsx +22 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickResponses.tsx +11 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolCall.tsx +14 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithToolResponse.tsx +222 -105
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +123 -14
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +1 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +3 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotHeaderDrawerWithSearchActions.tsx +198 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarCustomActions.tsx +190 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotMessageBarIndicatorThinking.tsx +15 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/CompactOnboarding.tsx +141 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/Onboarding.tsx +151 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/RH-Hat-Image.svg +9 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/Settings.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +81 -30
- package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +18 -18
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +44 -22
- package/patternfly-docs/content/extensions/chatbot/examples/demos/WhiteEmbeddedChatbot.tsx +451 -0
- package/patternfly-docs/patternfly-docs.config.js +1 -1
- package/patternfly-docs/patternfly-docs.source.js +1 -1
- package/src/AttachMenu/AttachMenu.tsx +26 -11
- package/src/Chatbot/Chatbot.scss +23 -1
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss +43 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx +95 -0
- package/src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx +51 -15
- package/src/ChatbotFooter/ChatbotFooter.scss +21 -0
- package/src/ChatbotFooter/ChatbotFooter.test.tsx +10 -1
- package/src/ChatbotFooter/ChatbotFooter.tsx +10 -3
- package/src/ChatbotHeader/ChatbotHeader.scss +19 -0
- package/src/ChatbotHeader/ChatbotHeaderMenu.tsx +56 -14
- package/src/ChatbotModal/ChatbotModal.scss +3 -0
- package/src/CodeModal/CodeModal.tsx +72 -23
- package/src/DeepThinking/DeepThinking.scss +1 -1
- package/src/DeepThinking/DeepThinking.test.tsx +109 -0
- package/src/DeepThinking/DeepThinking.tsx +54 -5
- package/src/FileDetailsLabel/FileDetailsLabel.tsx +2 -2
- package/src/MarkdownContent/MarkdownContent.test.tsx +207 -0
- package/src/MarkdownContent/MarkdownContent.tsx +269 -0
- package/src/MarkdownContent/index.ts +2 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +17 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.test.tsx +171 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +21 -5
- package/src/Message/ErrorMessage/ErrorMessage.test.tsx +38 -0
- package/src/Message/ErrorMessage/ErrorMessage.tsx +17 -2
- package/src/Message/LinkMessage/LinkMessage.scss +5 -0
- package/src/Message/LinkMessage/LinkMessage.tsx +24 -2
- package/src/Message/ListMessage/ListMessage.scss +8 -0
- package/src/Message/ListMessage/OrderedListMessage.tsx +16 -2
- package/src/Message/ListMessage/UnorderedListMessage.tsx +12 -2
- package/src/Message/Message.scss +11 -7
- package/src/Message/Message.test.tsx +239 -2
- package/src/Message/Message.tsx +133 -241
- package/src/Message/MessageAndActions/MessageAndActions.test.tsx +23 -0
- package/src/Message/MessageAndActions/MessageAndActions.tsx +22 -0
- package/src/Message/MessageAndActions/index.ts +1 -0
- package/src/Message/MessageAttachments/MessageAttachmentItem.test.tsx +23 -0
- package/src/Message/MessageAttachments/MessageAttachmentItem.tsx +25 -0
- package/src/Message/MessageAttachments/MessageAttachmentsContainer.test.tsx +23 -0
- package/src/Message/MessageAttachments/MessageAttachmentsContainer.tsx +25 -0
- package/src/Message/MessageAttachments/index.ts +2 -0
- package/src/Message/MessageInput.tsx +1 -1
- package/src/Message/MessageLoading.scss +7 -0
- package/src/Message/MessageLoading.test.tsx +23 -0
- package/src/Message/MessageLoading.tsx +17 -2
- package/src/Message/QuickResponse/QuickResponse.scss +3 -1
- package/src/Message/QuickResponse/QuickResponse.test.tsx +131 -0
- package/src/Message/QuickResponse/QuickResponse.tsx +3 -2
- package/src/Message/QuickResponse/index.ts +1 -0
- package/src/Message/QuickStarts/QuickStartTile.tsx +1 -1
- package/src/Message/QuickStarts/index.ts +2 -0
- package/src/Message/TableMessage/TableMessage.scss +17 -1
- package/src/Message/TableMessage/TableMessage.tsx +22 -2
- package/src/Message/TextMessage/TextMessage.scss +18 -0
- package/src/Message/TextMessage/TextMessage.tsx +39 -3
- package/src/Message/UserFeedback/UserFeedback.scss +30 -2
- package/src/Message/UserFeedback/UserFeedback.tsx +23 -13
- package/src/Message/UserFeedback/UserFeedbackComplete.tsx +1 -4
- package/src/Message/UserFeedback/index.ts +2 -0
- package/src/Message/index.ts +8 -0
- package/src/MessageBar/AttachButton.scss +0 -1
- package/src/MessageBar/AttachButton.test.tsx +4 -0
- package/src/MessageBar/AttachButton.tsx +4 -1
- package/src/MessageBar/MessageBar.scss +66 -6
- package/src/MessageBar/MessageBar.test.tsx +129 -1
- package/src/MessageBar/MessageBar.tsx +150 -56
- package/src/MessageBar/MicrophoneButton.scss +0 -1
- package/src/MessageBar/SendButton.scss +0 -1
- package/src/MessageBar/StopButton.scss +0 -1
- package/src/Onboarding/Onboarding.scss +101 -0
- package/src/Onboarding/Onboarding.test.tsx +148 -0
- package/src/Onboarding/Onboarding.tsx +126 -0
- package/src/Onboarding/index.ts +3 -0
- package/src/ResponseActions/ResponseActions.scss +12 -1
- package/src/ResponseActions/ResponseActions.test.tsx +111 -12
- package/src/ResponseActions/ResponseActions.tsx +44 -10
- package/src/ResponseActions/ResponseActionsGroups.test.tsx +23 -0
- package/src/ResponseActions/ResponseActionsGroups.tsx +28 -0
- package/src/ResponseActions/index.ts +1 -0
- package/src/ToolCall/ToolCall.scss +1 -1
- package/src/ToolCall/ToolCall.test.tsx +91 -0
- package/src/ToolCall/ToolCall.tsx +49 -4
- package/src/ToolResponse/ToolResponse.scss +13 -3
- package/src/ToolResponse/ToolResponse.test.tsx +119 -0
- package/src/ToolResponse/ToolResponse.tsx +82 -7
- package/src/__mocks__/monaco-editor.ts +19 -0
- package/src/index.ts +6 -0
- package/src/main.scss +2 -0
- package/tsconfig.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/about-chatbot.md +0 -44
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Markdown Content - Shared component for rendering markdown
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { type FunctionComponent, ReactNode } from 'react';
|
|
5
|
+
import Markdown, { Options } from 'react-markdown';
|
|
6
|
+
import remarkGfm from 'remark-gfm';
|
|
7
|
+
import { ContentVariants } from '@patternfly/react-core';
|
|
8
|
+
import CodeBlockMessage, { CodeBlockMessageProps } from '../Message/CodeBlockMessage/CodeBlockMessage';
|
|
9
|
+
import TextMessage from '../Message/TextMessage/TextMessage';
|
|
10
|
+
import ListItemMessage from '../Message/ListMessage/ListItemMessage';
|
|
11
|
+
import UnorderedListMessage from '../Message/ListMessage/UnorderedListMessage';
|
|
12
|
+
import OrderedListMessage from '../Message/ListMessage/OrderedListMessage';
|
|
13
|
+
import TableMessage from '../Message/TableMessage/TableMessage';
|
|
14
|
+
import TrMessage from '../Message/TableMessage/TrMessage';
|
|
15
|
+
import TdMessage from '../Message/TableMessage/TdMessage';
|
|
16
|
+
import TbodyMessage from '../Message/TableMessage/TbodyMessage';
|
|
17
|
+
import TheadMessage from '../Message/TableMessage/TheadMessage';
|
|
18
|
+
import ThMessage from '../Message/TableMessage/ThMessage';
|
|
19
|
+
import { TableProps } from '@patternfly/react-table';
|
|
20
|
+
import ImageMessage from '../Message/ImageMessage/ImageMessage';
|
|
21
|
+
import rehypeUnwrapImages from 'rehype-unwrap-images';
|
|
22
|
+
import rehypeExternalLinks from 'rehype-external-links';
|
|
23
|
+
import rehypeSanitize from 'rehype-sanitize';
|
|
24
|
+
import rehypeHighlight from 'rehype-highlight';
|
|
25
|
+
import 'highlight.js/styles/vs2015.css';
|
|
26
|
+
import { PluggableList } from 'unified';
|
|
27
|
+
import LinkMessage from '../Message/LinkMessage/LinkMessage';
|
|
28
|
+
import { rehypeMoveImagesOutOfParagraphs } from '../Message/Plugins/rehypeMoveImagesOutOfParagraphs';
|
|
29
|
+
import SuperscriptMessage from '../Message/SuperscriptMessage/SuperscriptMessage';
|
|
30
|
+
import { ButtonProps } from '@patternfly/react-core';
|
|
31
|
+
import { css } from '@patternfly/react-styles';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* MarkdownContent renders content either as plain text or with content with markdown support.
|
|
35
|
+
*
|
|
36
|
+
* Use this component when passing children to Message to customize its structure.
|
|
37
|
+
*/
|
|
38
|
+
export interface MarkdownContentProps {
|
|
39
|
+
/** The content to render. Supports markdown formatting by default, or plain text when isMarkdownDisabled is true. */
|
|
40
|
+
content?: string;
|
|
41
|
+
/** Disables markdown parsing, allowing only plain text input */
|
|
42
|
+
isMarkdownDisabled?: boolean;
|
|
43
|
+
/** Props for code blocks */
|
|
44
|
+
codeBlockProps?: CodeBlockMessageProps;
|
|
45
|
+
/** Props for table message. It is important to include a detailed aria-label that describes the purpose of the table. */
|
|
46
|
+
tableProps?: Required<Pick<TableProps, 'aria-label'>> & TableProps;
|
|
47
|
+
/** Additional rehype plugins passed from the consumer */
|
|
48
|
+
additionalRehypePlugins?: PluggableList;
|
|
49
|
+
/** Additional remark plugins passed from the consumer */
|
|
50
|
+
additionalRemarkPlugins?: PluggableList;
|
|
51
|
+
/** Whether to open links in message in new tab. */
|
|
52
|
+
openLinkInNewTab?: boolean;
|
|
53
|
+
/** Props for links */
|
|
54
|
+
linkProps?: ButtonProps;
|
|
55
|
+
/** Allows passing additional props down to markdown parser react-markdown, such as allowedElements and disallowedElements. See https://github.com/remarkjs/react-markdown?tab=readme-ov-file#options for options */
|
|
56
|
+
reactMarkdownProps?: Options;
|
|
57
|
+
/** Allows passing additional props down to remark-gfm. See https://github.com/remarkjs/remark-gfm?tab=readme-ov-file#options for options */
|
|
58
|
+
remarkGfmProps?: Options;
|
|
59
|
+
/** Whether to strip out images in markdown */
|
|
60
|
+
hasNoImages?: boolean;
|
|
61
|
+
/** Sets background colors to be appropriate on primary chatbot background */
|
|
62
|
+
isPrimary?: boolean;
|
|
63
|
+
/** Custom component to render when markdown is disabled */
|
|
64
|
+
textComponent?: ReactNode;
|
|
65
|
+
/** Flag indicating whether content should retain various styles of its context (typically font-size and text color). */
|
|
66
|
+
shouldRetainStyles?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const MarkdownContent: FunctionComponent<MarkdownContentProps> = ({
|
|
70
|
+
content,
|
|
71
|
+
isMarkdownDisabled,
|
|
72
|
+
codeBlockProps,
|
|
73
|
+
tableProps,
|
|
74
|
+
openLinkInNewTab = true,
|
|
75
|
+
additionalRehypePlugins = [],
|
|
76
|
+
additionalRemarkPlugins = [],
|
|
77
|
+
linkProps,
|
|
78
|
+
reactMarkdownProps,
|
|
79
|
+
remarkGfmProps,
|
|
80
|
+
hasNoImages = false,
|
|
81
|
+
isPrimary,
|
|
82
|
+
textComponent,
|
|
83
|
+
shouldRetainStyles
|
|
84
|
+
}: MarkdownContentProps) => {
|
|
85
|
+
let rehypePlugins: PluggableList = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs, rehypeHighlight];
|
|
86
|
+
if (openLinkInNewTab) {
|
|
87
|
+
rehypePlugins = rehypePlugins.concat([[rehypeExternalLinks, { target: '_blank' }, rehypeSanitize]]);
|
|
88
|
+
}
|
|
89
|
+
if (additionalRehypePlugins) {
|
|
90
|
+
rehypePlugins.push(...additionalRehypePlugins);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const disallowedElements = hasNoImages ? ['img'] : [];
|
|
94
|
+
if (reactMarkdownProps && reactMarkdownProps.disallowedElements) {
|
|
95
|
+
disallowedElements.push(...reactMarkdownProps.disallowedElements);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (isMarkdownDisabled) {
|
|
99
|
+
if (textComponent) {
|
|
100
|
+
return <>{textComponent}</>;
|
|
101
|
+
}
|
|
102
|
+
return (
|
|
103
|
+
<TextMessage component={ContentVariants.p} isPrimary={isPrimary}>
|
|
104
|
+
{content}
|
|
105
|
+
</TextMessage>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<Markdown
|
|
111
|
+
components={{
|
|
112
|
+
section: (props) => {
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
114
|
+
const { node, ...rest } = props;
|
|
115
|
+
return (
|
|
116
|
+
<section
|
|
117
|
+
{...rest}
|
|
118
|
+
className={css('pf-chatbot__message-text', shouldRetainStyles && 'pf-m-markdown', rest?.className)}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
},
|
|
122
|
+
p: (props) => {
|
|
123
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
124
|
+
const { node, ...rest } = props;
|
|
125
|
+
return (
|
|
126
|
+
<TextMessage
|
|
127
|
+
shouldRetainStyles={shouldRetainStyles}
|
|
128
|
+
component={ContentVariants.p}
|
|
129
|
+
{...rest}
|
|
130
|
+
isPrimary={isPrimary}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
code: ({ children, ...props }) => {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
136
|
+
const { node, ...codeProps } = props;
|
|
137
|
+
return (
|
|
138
|
+
<CodeBlockMessage
|
|
139
|
+
{...codeProps}
|
|
140
|
+
{...codeBlockProps}
|
|
141
|
+
isPrimary={isPrimary}
|
|
142
|
+
shouldRetainStyles={shouldRetainStyles}
|
|
143
|
+
>
|
|
144
|
+
{children}
|
|
145
|
+
</CodeBlockMessage>
|
|
146
|
+
);
|
|
147
|
+
},
|
|
148
|
+
h1: (props) => {
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
150
|
+
const { node, ...rest } = props;
|
|
151
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h1} {...rest} />;
|
|
152
|
+
},
|
|
153
|
+
h2: (props) => {
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
155
|
+
const { node, ...rest } = props;
|
|
156
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h2} {...rest} />;
|
|
157
|
+
},
|
|
158
|
+
h3: (props) => {
|
|
159
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
160
|
+
const { node, ...rest } = props;
|
|
161
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h3} {...rest} />;
|
|
162
|
+
},
|
|
163
|
+
h4: (props) => {
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
165
|
+
const { node, ...rest } = props;
|
|
166
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h4} {...rest} />;
|
|
167
|
+
},
|
|
168
|
+
h5: (props) => {
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
170
|
+
const { node, ...rest } = props;
|
|
171
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h5} {...rest} />;
|
|
172
|
+
},
|
|
173
|
+
h6: (props) => {
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
175
|
+
const { node, ...rest } = props;
|
|
176
|
+
return <TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.h6} {...rest} />;
|
|
177
|
+
},
|
|
178
|
+
blockquote: (props) => {
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
180
|
+
const { node, ...rest } = props;
|
|
181
|
+
return (
|
|
182
|
+
<TextMessage shouldRetainStyles={shouldRetainStyles} component={ContentVariants.blockquote} {...rest} />
|
|
183
|
+
);
|
|
184
|
+
},
|
|
185
|
+
ul: (props) => {
|
|
186
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
187
|
+
const { node, ...rest } = props;
|
|
188
|
+
return <UnorderedListMessage shouldRetainStyles={shouldRetainStyles} {...rest} />;
|
|
189
|
+
},
|
|
190
|
+
ol: (props) => {
|
|
191
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
192
|
+
const { node, ...rest } = props;
|
|
193
|
+
return <OrderedListMessage shouldRetainStyles={shouldRetainStyles} {...rest} />;
|
|
194
|
+
},
|
|
195
|
+
li: (props) => {
|
|
196
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
197
|
+
const { node, ...rest } = props;
|
|
198
|
+
return <ListItemMessage {...rest} />;
|
|
199
|
+
},
|
|
200
|
+
// table requires node attribute for calculating headers for mobile breakpoint
|
|
201
|
+
table: (props) => (
|
|
202
|
+
<TableMessage shouldRetainStyles={shouldRetainStyles} {...props} {...tableProps} isPrimary={isPrimary} />
|
|
203
|
+
),
|
|
204
|
+
tbody: (props) => {
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
206
|
+
const { node, ...rest } = props;
|
|
207
|
+
return <TbodyMessage {...rest} />;
|
|
208
|
+
},
|
|
209
|
+
thead: (props) => {
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
211
|
+
const { node, ...rest } = props;
|
|
212
|
+
return <TheadMessage {...rest} />;
|
|
213
|
+
},
|
|
214
|
+
tr: (props) => {
|
|
215
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
216
|
+
const { node, ...rest } = props;
|
|
217
|
+
return <TrMessage {...rest} />;
|
|
218
|
+
},
|
|
219
|
+
td: (props) => {
|
|
220
|
+
// Conflicts with Td type
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
222
|
+
const { node, width, ...rest } = props;
|
|
223
|
+
return <TdMessage {...rest} />;
|
|
224
|
+
},
|
|
225
|
+
th: (props) => {
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
227
|
+
const { node, ...rest } = props;
|
|
228
|
+
return <ThMessage {...rest} />;
|
|
229
|
+
},
|
|
230
|
+
img: (props) => {
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
232
|
+
const { node, ...rest } = props;
|
|
233
|
+
return <ImageMessage {...rest} />;
|
|
234
|
+
},
|
|
235
|
+
a: (props) => {
|
|
236
|
+
// node is just the details of the document structure - not needed
|
|
237
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
238
|
+
const { node, ...rest } = props;
|
|
239
|
+
return (
|
|
240
|
+
// some a types conflict with ButtonProps, but it's ok because we are using an a tag
|
|
241
|
+
// there are too many to handle manually
|
|
242
|
+
<LinkMessage shouldRetainStyles={shouldRetainStyles} {...(rest as any)} {...linkProps}>
|
|
243
|
+
{props.children}
|
|
244
|
+
</LinkMessage>
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
// used for footnotes
|
|
248
|
+
sup: (props) => {
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
250
|
+
const { node, ...rest } = props;
|
|
251
|
+
return <SuperscriptMessage {...rest} />;
|
|
252
|
+
}
|
|
253
|
+
}}
|
|
254
|
+
remarkPlugins={[[remarkGfm, { ...remarkGfmProps }], ...additionalRemarkPlugins]}
|
|
255
|
+
rehypePlugins={rehypePlugins}
|
|
256
|
+
{...reactMarkdownProps}
|
|
257
|
+
remarkRehypeOptions={{
|
|
258
|
+
// removes sr-only class from footnote labels applied by default
|
|
259
|
+
footnoteLabelProperties: { className: [''] },
|
|
260
|
+
...reactMarkdownProps?.remarkRehypeOptions
|
|
261
|
+
}}
|
|
262
|
+
disallowedElements={disallowedElements}
|
|
263
|
+
>
|
|
264
|
+
{content}
|
|
265
|
+
</Markdown>
|
|
266
|
+
);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export default MarkdownContent;
|
|
@@ -75,12 +75,29 @@
|
|
|
75
75
|
overflow: hidden !important;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
&.pf-m-markdown .pf-v6-c-code-block__code {
|
|
80
|
+
font-size: inherit;
|
|
81
|
+
}
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
.pf-chatbot__message-inline-code {
|
|
81
85
|
--pf-chatbot-message-text-inline-code-font-size: var(--pf-t--global--font--size--body--default);
|
|
86
|
+
|
|
82
87
|
background-color: var(--pf-t--global--background--color--tertiary--default);
|
|
83
88
|
font-size: var(--pf-chatbot-message-text-inline-code-font-size);
|
|
89
|
+
border: var(--pf-t--global--border--width--high-contrast--regular) solid
|
|
90
|
+
var(--pf-t--global--border--color--high-contrast);
|
|
91
|
+
border-radius: var(--pf-t--global--border--radius--small);
|
|
92
|
+
padding-block-start: var(--pf-t--global--spacer--xs);
|
|
93
|
+
padding-block-end: var(--pf-t--global--spacer--xs);
|
|
94
|
+
padding-inline-start: var(--pf-t--global--spacer--xs);
|
|
95
|
+
padding-inline-end: var(--pf-t--global--spacer--xs);
|
|
96
|
+
word-break: break-word;
|
|
97
|
+
|
|
98
|
+
&.pf-m-primary {
|
|
99
|
+
background-color: var(--pf-t--global--background--color--secondary--default);
|
|
100
|
+
}
|
|
84
101
|
}
|
|
85
102
|
|
|
86
103
|
.pf-chatbot__message-code-toggle {
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import CodeBlockMessage from './CodeBlockMessage';
|
|
5
|
+
|
|
6
|
+
// Mock clipboard API
|
|
7
|
+
Object.assign(navigator, {
|
|
8
|
+
clipboard: {
|
|
9
|
+
writeText: jest.fn()
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('CodeBlockMessage', () => {
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
jest.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should render inline code for single-line content', () => {
|
|
19
|
+
render(<CodeBlockMessage className="language-javascript">const x = 5;</CodeBlockMessage>);
|
|
20
|
+
const code = screen.getByText('const x = 5;');
|
|
21
|
+
expect(code.tagName).toBe('CODE');
|
|
22
|
+
expect(code).toHaveClass('pf-chatbot__message-inline-code');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should render code block for multi-line content', () => {
|
|
26
|
+
const multilineCode = 'const x = 5;\nconst y = 10;';
|
|
27
|
+
const { container } = render(<CodeBlockMessage className="language-javascript">{multilineCode}</CodeBlockMessage>);
|
|
28
|
+
const codeElement = container.querySelector('code');
|
|
29
|
+
expect(codeElement?.textContent).toBe(multilineCode);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should display language label', () => {
|
|
33
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
34
|
+
render(<CodeBlockMessage className="language-javascript">{code}</CodeBlockMessage>);
|
|
35
|
+
expect(screen.getByText('javascript')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should render copy button', () => {
|
|
39
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
40
|
+
render(<CodeBlockMessage>{code}</CodeBlockMessage>);
|
|
41
|
+
expect(screen.getByRole('button', { name: 'Copy code' })).toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should copy plain string content to clipboard', async () => {
|
|
45
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
46
|
+
render(<CodeBlockMessage>{code}</CodeBlockMessage>);
|
|
47
|
+
|
|
48
|
+
const copyButton = screen.getByRole('button', { name: 'Copy code' });
|
|
49
|
+
await userEvent.click(copyButton);
|
|
50
|
+
|
|
51
|
+
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(code);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should extract text content from React elements when copying', async () => {
|
|
55
|
+
// Simulate what happens with syntax highlighting - children become React elements
|
|
56
|
+
const { container } = render(
|
|
57
|
+
<CodeBlockMessage className="language-javascript">
|
|
58
|
+
<span className="hljs-keyword">const</span> x = 5;{'\n'}
|
|
59
|
+
<span className="hljs-keyword">const</span> y = 10;
|
|
60
|
+
</CodeBlockMessage>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const copyButton = screen.getByRole('button', { name: 'Copy code' });
|
|
64
|
+
await userEvent.click(copyButton);
|
|
65
|
+
|
|
66
|
+
// Should extract actual text content from DOM, not "[object Object]"
|
|
67
|
+
const codeElement = container.querySelector('code');
|
|
68
|
+
const expectedText = codeElement?.textContent || '';
|
|
69
|
+
expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expectedText);
|
|
70
|
+
expect(expectedText).not.toContain('[object Object]');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should show check icon after copying', async () => {
|
|
74
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
75
|
+
render(<CodeBlockMessage>{code}</CodeBlockMessage>);
|
|
76
|
+
|
|
77
|
+
const copyButton = screen.getByRole('button', { name: 'Copy code' });
|
|
78
|
+
await userEvent.click(copyButton);
|
|
79
|
+
|
|
80
|
+
// Check icon should be visible (we can verify by checking if CopyIcon is not present)
|
|
81
|
+
const svgElement = copyButton.querySelector('svg');
|
|
82
|
+
expect(svgElement).toBeInTheDocument();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should render expandable section when isExpandable is true', () => {
|
|
86
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
87
|
+
render(<CodeBlockMessage isExpandable>{code}</CodeBlockMessage>);
|
|
88
|
+
|
|
89
|
+
expect(screen.getByRole('button', { name: 'Show more' })).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should toggle expandable section', async () => {
|
|
93
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
94
|
+
render(<CodeBlockMessage isExpandable>{code}</CodeBlockMessage>);
|
|
95
|
+
|
|
96
|
+
const toggleButton = screen.getByRole('button', { name: 'Show more' });
|
|
97
|
+
await userEvent.click(toggleButton);
|
|
98
|
+
|
|
99
|
+
expect(screen.getByRole('button', { name: 'Show less' })).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should use custom expanded/collapsed text', () => {
|
|
103
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
104
|
+
render(
|
|
105
|
+
<CodeBlockMessage isExpandable expandedText="Hide" collapsedText="Reveal">
|
|
106
|
+
{code}
|
|
107
|
+
</CodeBlockMessage>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(screen.getByRole('button', { name: 'Reveal' })).toBeInTheDocument();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should pass through expandableSectionProps', () => {
|
|
114
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
115
|
+
const { container } = render(
|
|
116
|
+
<CodeBlockMessage isExpandable expandableSectionProps={{ className: 'custom-expandable-class' }}>
|
|
117
|
+
{code}
|
|
118
|
+
</CodeBlockMessage>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const expandableSection = container.querySelector('.pf-v6-c-expandable-section.custom-expandable-class');
|
|
122
|
+
expect(expandableSection).toBeInTheDocument();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should render custom actions', () => {
|
|
126
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
127
|
+
const customAction = <button aria-label="Custom action">Custom</button>;
|
|
128
|
+
render(<CodeBlockMessage customActions={customAction}>{code}</CodeBlockMessage>);
|
|
129
|
+
|
|
130
|
+
expect(screen.getByRole('button', { name: 'Custom action' })).toBeInTheDocument();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should apply isPrimary class to inline code', () => {
|
|
134
|
+
render(<CodeBlockMessage isPrimary>const x = 5;</CodeBlockMessage>);
|
|
135
|
+
const code = screen.getByText('const x = 5;');
|
|
136
|
+
expect(code).toHaveClass('pf-m-primary');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should apply shouldRetainStyles class to code block', () => {
|
|
140
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
141
|
+
const { container } = render(<CodeBlockMessage shouldRetainStyles>{code}</CodeBlockMessage>);
|
|
142
|
+
|
|
143
|
+
const codeBlockDiv = container.querySelector('.pf-chatbot__message-code-block');
|
|
144
|
+
expect(codeBlockDiv).toHaveClass('pf-m-markdown');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should use custom aria-label for copy button', () => {
|
|
148
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
149
|
+
render(<CodeBlockMessage aria-label="Copy this code">{code}</CodeBlockMessage>);
|
|
150
|
+
|
|
151
|
+
expect(screen.getByRole('button', { name: 'Copy this code' })).toBeInTheDocument();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should prioritize data-expanded-text over expandedText prop', () => {
|
|
155
|
+
const code = 'const x = 5;\nconst y = 10;';
|
|
156
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn());
|
|
157
|
+
|
|
158
|
+
render(
|
|
159
|
+
<CodeBlockMessage isExpandable expandedText="Custom Expanded" data-expanded-text="Data Expanded">
|
|
160
|
+
{code}
|
|
161
|
+
</CodeBlockMessage>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
165
|
+
'Message:',
|
|
166
|
+
expect.stringContaining('data-expanded-text or data-collapsed-text will override')
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
consoleErrorSpy.mockRestore();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
|
|
20
20
|
import { CheckIcon } from '@patternfly/react-icons/dist/esm/icons/check-icon';
|
|
21
21
|
import { CopyIcon } from '@patternfly/react-icons/dist/esm/icons/copy-icon';
|
|
22
|
+
import { css } from '@patternfly/react-styles';
|
|
22
23
|
|
|
23
24
|
export interface CodeBlockMessageProps {
|
|
24
25
|
/** Content rendered in code block */
|
|
@@ -39,6 +40,10 @@ export interface CodeBlockMessageProps {
|
|
|
39
40
|
collapsedText?: string;
|
|
40
41
|
/** Custom actions added to header of code block, after any default actions such as the "copy" action. */
|
|
41
42
|
customActions?: React.ReactNode;
|
|
43
|
+
/** Sets background colors to be appropriate on primary chatbot background */
|
|
44
|
+
isPrimary?: boolean;
|
|
45
|
+
/** Flag indicating that the content should retain message styles when using Markdown. */
|
|
46
|
+
shouldRetainStyles?: boolean;
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
const DEFAULT_EXPANDED_TEXT = 'Show less';
|
|
@@ -54,6 +59,8 @@ const CodeBlockMessage = ({
|
|
|
54
59
|
expandedText = DEFAULT_EXPANDED_TEXT,
|
|
55
60
|
collapsedText = DEFAULT_COLLAPSED_TEXT,
|
|
56
61
|
customActions,
|
|
62
|
+
isPrimary,
|
|
63
|
+
shouldRetainStyles,
|
|
57
64
|
...props
|
|
58
65
|
}: CodeBlockMessageProps) => {
|
|
59
66
|
const [copied, setCopied] = useState(false);
|
|
@@ -85,13 +92,22 @@ const CodeBlockMessage = ({
|
|
|
85
92
|
);
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
const onToggle = (isExpanded) => {
|
|
95
|
+
const onToggle = (isExpanded: boolean) => {
|
|
89
96
|
setIsExpanded(isExpanded);
|
|
90
97
|
};
|
|
91
98
|
|
|
92
99
|
// Handle clicking copy button
|
|
93
|
-
const handleCopy = useCallback((
|
|
94
|
-
|
|
100
|
+
const handleCopy = useCallback((_event: React.MouseEvent, text: React.ReactNode) => {
|
|
101
|
+
let textToCopy = '';
|
|
102
|
+
if (typeof text === 'string') {
|
|
103
|
+
textToCopy = text;
|
|
104
|
+
} else {
|
|
105
|
+
if (codeBlockRef.current) {
|
|
106
|
+
const codeElement = codeBlockRef.current.querySelector('code');
|
|
107
|
+
textToCopy = codeElement?.textContent || '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
navigator.clipboard.writeText(textToCopy);
|
|
95
111
|
setCopied(true);
|
|
96
112
|
}, []);
|
|
97
113
|
|
|
@@ -108,7 +124,7 @@ const CodeBlockMessage = ({
|
|
|
108
124
|
|
|
109
125
|
if (!String(children).includes('\n')) {
|
|
110
126
|
return (
|
|
111
|
-
<code {...props} className=
|
|
127
|
+
<code {...props} className={`pf-chatbot__message-inline-code ${isPrimary ? 'pf-m-primary' : ''}`}>
|
|
112
128
|
{children}
|
|
113
129
|
</code>
|
|
114
130
|
);
|
|
@@ -135,7 +151,7 @@ const CodeBlockMessage = ({
|
|
|
135
151
|
);
|
|
136
152
|
|
|
137
153
|
return (
|
|
138
|
-
<div className=
|
|
154
|
+
<div className={css('pf-chatbot__message-code-block', shouldRetainStyles && 'pf-m-markdown')} ref={codeBlockRef}>
|
|
139
155
|
<CodeBlock actions={actions}>
|
|
140
156
|
<CodeBlockCode>
|
|
141
157
|
<>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
import ErrorMessage from './ErrorMessage';
|
|
4
|
+
|
|
5
|
+
test('Renders with title', () => {
|
|
6
|
+
render(<ErrorMessage title="Error occurred" />);
|
|
7
|
+
|
|
8
|
+
expect(screen.getByText('Error occurred')).toBeVisible();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('Renders with children', () => {
|
|
12
|
+
render(<ErrorMessage title="Error occurred">This is the error message body</ErrorMessage>);
|
|
13
|
+
|
|
14
|
+
expect(screen.getByText('This is the error message body')).toBeVisible();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Renders with action links', () => {
|
|
18
|
+
const actionLinks = (
|
|
19
|
+
<a href="#retry" data-testid="retry-link">
|
|
20
|
+
Retry action link
|
|
21
|
+
</a>
|
|
22
|
+
);
|
|
23
|
+
render(<ErrorMessage title="Error occurred" actionLinks={actionLinks} />);
|
|
24
|
+
|
|
25
|
+
expect(screen.getByText('Retry action link')).toBeVisible();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('Renders with custom className', () => {
|
|
29
|
+
render(<ErrorMessage title="Error occurred" className="custom-error-class" />);
|
|
30
|
+
|
|
31
|
+
expect(screen.getByText('Error occurred').parentElement).toHaveClass('custom-error-class');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('Renders with spread props', () => {
|
|
35
|
+
render(<ErrorMessage title="Error occurred" id="test-error-id" />);
|
|
36
|
+
|
|
37
|
+
expect(screen.getByText('Error occurred').parentElement).toHaveAttribute('id', 'test-error-id');
|
|
38
|
+
});
|
|
@@ -4,8 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
import { Alert, AlertProps } from '@patternfly/react-core';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* ErrorMessage displays an inline danger alert for error states in messages.
|
|
9
|
+
* Use this component when passing children to Message to display error information.
|
|
10
|
+
*/
|
|
11
|
+
export interface ErrorMessageProps extends Partial<AlertProps> {
|
|
12
|
+
/** Content to display in the error alert body */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Additional classes for the error alert */
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Title of the error alert */
|
|
17
|
+
title?: React.ReactNode;
|
|
18
|
+
/** Action links to display in the alert footer */
|
|
19
|
+
actionLinks?: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const ErrorMessage = ({ title, actionLinks, children, className, ...props }: ErrorMessageProps) => (
|
|
23
|
+
<Alert isInline variant="danger" title={title} actionLinks={actionLinks} className={className} {...props}>
|
|
9
24
|
{children}
|
|
10
25
|
</Alert>
|
|
11
26
|
);
|
|
@@ -5,8 +5,21 @@
|
|
|
5
5
|
import { Button, ButtonProps } from '@patternfly/react-core';
|
|
6
6
|
import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
|
|
7
7
|
import { ExtraProps } from 'react-markdown';
|
|
8
|
+
import { css } from '@patternfly/react-styles';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
export interface LinkMessageProps {
|
|
11
|
+
/** Flag indicating that the content should retain message styles when using Markdown. */
|
|
12
|
+
shouldRetainStyles?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const LinkMessage = ({
|
|
16
|
+
children,
|
|
17
|
+
target,
|
|
18
|
+
href,
|
|
19
|
+
id,
|
|
20
|
+
shouldRetainStyles,
|
|
21
|
+
...props
|
|
22
|
+
}: LinkMessageProps & ButtonProps & ExtraProps) => {
|
|
10
23
|
if (target === '_blank') {
|
|
11
24
|
return (
|
|
12
25
|
<Button
|
|
@@ -20,6 +33,7 @@ const LinkMessage = ({ children, target, href, id, ...props }: ButtonProps & Ext
|
|
|
20
33
|
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
21
34
|
id={id}
|
|
22
35
|
{...props}
|
|
36
|
+
className={css(shouldRetainStyles && 'pf-m-markdown', props?.className)}
|
|
23
37
|
>
|
|
24
38
|
{children}
|
|
25
39
|
</Button>
|
|
@@ -28,7 +42,15 @@ const LinkMessage = ({ children, target, href, id, ...props }: ButtonProps & Ext
|
|
|
28
42
|
|
|
29
43
|
return (
|
|
30
44
|
// need to explicitly call this out or id doesn't seem to get passed - required for footnotes
|
|
31
|
-
<Button
|
|
45
|
+
<Button
|
|
46
|
+
isInline
|
|
47
|
+
component="a"
|
|
48
|
+
href={href}
|
|
49
|
+
variant="link"
|
|
50
|
+
id={id}
|
|
51
|
+
{...props}
|
|
52
|
+
className={css(shouldRetainStyles && 'pf-m-markdown', props?.className)}
|
|
53
|
+
>
|
|
32
54
|
{children}
|
|
33
55
|
</Button>
|
|
34
56
|
);
|