@patternfly/chatbot 6.5.0-prerelease.21 → 6.5.0-prerelease.23
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/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/MarkdownContent/MarkdownContent.d.ts +39 -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 +3 -1
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +3 -2
- 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.js +2 -155
- package/dist/cjs/Message/TableMessage/TableMessage.d.ts +6 -1
- package/dist/cjs/Message/TableMessage/TableMessage.js +3 -2
- package/dist/cjs/Message/TextMessage/TextMessage.d.ts +8 -1
- package/dist/cjs/Message/TextMessage/TextMessage.js +3 -2
- 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/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -1
- package/dist/css/main.css +48 -0
- package/dist/css/main.css.map +1 -1
- package/dist/dynamic/MarkdownContent/package.json +1 -0
- 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/MarkdownContent/MarkdownContent.d.ts +39 -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 +3 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +3 -2
- 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.js +3 -156
- package/dist/esm/Message/TableMessage/TableMessage.d.ts +6 -1
- package/dist/esm/Message/TableMessage/TableMessage.js +3 -2
- package/dist/esm/Message/TextMessage/TextMessage.d.ts +8 -1
- package/dist/esm/Message/TextMessage/TextMessage.js +3 -2
- 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/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithDeepThinking.tsx +25 -11
- 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/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 +32 -0
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +15 -1
- package/src/DeepThinking/DeepThinking.test.tsx +109 -0
- package/src/DeepThinking/DeepThinking.tsx +54 -5
- package/src/MarkdownContent/MarkdownContent.test.tsx +207 -0
- package/src/MarkdownContent/MarkdownContent.tsx +264 -0
- package/src/MarkdownContent/index.ts +2 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +4 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +5 -1
- 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.tsx +21 -181
- package/src/Message/TableMessage/TableMessage.scss +11 -0
- package/src/Message/TableMessage/TableMessage.tsx +18 -2
- package/src/Message/TextMessage/TextMessage.scss +8 -0
- package/src/Message/TextMessage/TextMessage.tsx +29 -2
- package/src/ToolCall/ToolCall.test.tsx +91 -0
- package/src/ToolCall/ToolCall.tsx +49 -4
- package/src/ToolResponse/ToolResponse.scss +10 -0
- package/src/ToolResponse/ToolResponse.test.tsx +119 -0
- package/src/ToolResponse/ToolResponse.tsx +82 -7
- package/src/index.ts +3 -0
- package/src/main.scss +1 -0
|
@@ -14,43 +14,23 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
14
|
// Chatbot Main - Message
|
|
15
15
|
// ============================================================================
|
|
16
16
|
import { forwardRef, useEffect, useState } from 'react';
|
|
17
|
-
import
|
|
18
|
-
import remarkGfm from 'remark-gfm';
|
|
19
|
-
import { Avatar, ContentVariants, Label, Timestamp, Truncate } from '@patternfly/react-core';
|
|
17
|
+
import { Avatar, Label, Timestamp, Truncate } from '@patternfly/react-core';
|
|
20
18
|
import MessageLoading from './MessageLoading';
|
|
21
|
-
import CodeBlockMessage from './CodeBlockMessage/CodeBlockMessage';
|
|
22
|
-
import TextMessage from './TextMessage/TextMessage';
|
|
23
19
|
import FileDetailsLabel from '../FileDetailsLabel/FileDetailsLabel';
|
|
24
20
|
import ResponseActions from '../ResponseActions/ResponseActions';
|
|
25
21
|
import SourcesCard from '../SourcesCard';
|
|
26
|
-
import ListItemMessage from './ListMessage/ListItemMessage';
|
|
27
|
-
import UnorderedListMessage from './ListMessage/UnorderedListMessage';
|
|
28
|
-
import OrderedListMessage from './ListMessage/OrderedListMessage';
|
|
29
22
|
import QuickStartTile from './QuickStarts/QuickStartTile';
|
|
30
23
|
import QuickResponse from './QuickResponse/QuickResponse';
|
|
31
24
|
import UserFeedback from './UserFeedback/UserFeedback';
|
|
32
25
|
import UserFeedbackComplete from './UserFeedback/UserFeedbackComplete';
|
|
33
|
-
import TableMessage from './TableMessage/TableMessage';
|
|
34
|
-
import TrMessage from './TableMessage/TrMessage';
|
|
35
|
-
import TdMessage from './TableMessage/TdMessage';
|
|
36
|
-
import TbodyMessage from './TableMessage/TbodyMessage';
|
|
37
|
-
import TheadMessage from './TableMessage/TheadMessage';
|
|
38
|
-
import ThMessage from './TableMessage/ThMessage';
|
|
39
|
-
import ImageMessage from './ImageMessage/ImageMessage';
|
|
40
|
-
import rehypeUnwrapImages from 'rehype-unwrap-images';
|
|
41
|
-
import rehypeExternalLinks from 'rehype-external-links';
|
|
42
|
-
import rehypeSanitize from 'rehype-sanitize';
|
|
43
|
-
import rehypeHighlight from 'rehype-highlight';
|
|
44
26
|
// see the full list of styles here: https://highlightjs.org/examples
|
|
45
27
|
import 'highlight.js/styles/vs2015.css';
|
|
46
|
-
import LinkMessage from './LinkMessage/LinkMessage';
|
|
47
28
|
import ErrorMessage from './ErrorMessage/ErrorMessage';
|
|
48
29
|
import MessageInput from './MessageInput';
|
|
49
|
-
import { rehypeMoveImagesOutOfParagraphs } from './Plugins/rehypeMoveImagesOutOfParagraphs';
|
|
50
30
|
import ToolResponse from '../ToolResponse';
|
|
51
31
|
import DeepThinking from '../DeepThinking';
|
|
52
|
-
import SuperscriptMessage from './SuperscriptMessage/SuperscriptMessage';
|
|
53
32
|
import ToolCall from '../ToolCall';
|
|
33
|
+
import MarkdownContent from '../MarkdownContent';
|
|
54
34
|
export const MessageBase = (_a) => {
|
|
55
35
|
var { role, content, extraContent, name, avatar, timestamp, isLoading, actions, persistActionSelection, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps, quickStarts, userFeedbackForm, userFeedbackComplete, isLiveRegion = true, innerRef, tableProps, openLinkInNewTab = true, additionalRehypePlugins = [], additionalRemarkPlugins = [], linkProps, error, isEditable, editPlaceholder = 'Edit prompt message...', updateWord = 'Update', cancelWord = 'Cancel', onEditUpdate, onEditCancel, inputRef, editFormProps, isCompact, isMarkdownDisabled, reactMarkdownProps, toolResponse, deepThinking, remarkGfmProps, toolCall, hasNoImagesInUserMessages = true, isPrimary } = _a, props = __rest(_a, ["role", "content", "extraContent", "name", "avatar", "timestamp", "isLoading", "actions", "persistActionSelection", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps", "quickStarts", "userFeedbackForm", "userFeedbackComplete", "isLiveRegion", "innerRef", "tableProps", "openLinkInNewTab", "additionalRehypePlugins", "additionalRemarkPlugins", "linkProps", "error", "isEditable", "editPlaceholder", "updateWord", "cancelWord", "onEditUpdate", "onEditCancel", "inputRef", "editFormProps", "isCompact", "isMarkdownDisabled", "reactMarkdownProps", "toolResponse", "deepThinking", "remarkGfmProps", "toolCall", "hasNoImagesInUserMessages", "isPrimary"]);
|
|
56
36
|
const [messageText, setMessageText] = useState(content);
|
|
@@ -58,13 +38,6 @@ export const MessageBase = (_a) => {
|
|
|
58
38
|
setMessageText(content);
|
|
59
39
|
}, [content]);
|
|
60
40
|
const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
|
|
61
|
-
let rehypePlugins = [rehypeUnwrapImages, rehypeMoveImagesOutOfParagraphs, rehypeHighlight];
|
|
62
|
-
if (openLinkInNewTab) {
|
|
63
|
-
rehypePlugins = rehypePlugins.concat([[rehypeExternalLinks, { target: '_blank' }, rehypeSanitize]]);
|
|
64
|
-
}
|
|
65
|
-
if (additionalRehypePlugins) {
|
|
66
|
-
rehypePlugins.push(...additionalRehypePlugins);
|
|
67
|
-
}
|
|
68
41
|
let avatarClassName;
|
|
69
42
|
if (avatarProps && 'className' in avatarProps) {
|
|
70
43
|
const { className } = avatarProps, rest = __rest(avatarProps, ["className"]);
|
|
@@ -74,133 +47,7 @@ export const MessageBase = (_a) => {
|
|
|
74
47
|
// Keep timestamps consistent between Timestamp component and aria-label
|
|
75
48
|
const date = new Date();
|
|
76
49
|
const dateString = timestamp !== null && timestamp !== void 0 ? timestamp : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
|
77
|
-
const
|
|
78
|
-
if (reactMarkdownProps && reactMarkdownProps.disallowedElements) {
|
|
79
|
-
disallowedElements.push(...reactMarkdownProps.disallowedElements);
|
|
80
|
-
}
|
|
81
|
-
const handleMarkdown = () => {
|
|
82
|
-
if (isMarkdownDisabled) {
|
|
83
|
-
return (_jsx(TextMessage, Object.assign({ component: ContentVariants.p }, props, { children: messageText })));
|
|
84
|
-
}
|
|
85
|
-
return (_jsx(Markdown, Object.assign({ components: {
|
|
86
|
-
section: (props) => {
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
88
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
89
|
-
return _jsx("section", Object.assign({}, rest, { className: `pf-chatbot__message-text ${rest === null || rest === void 0 ? void 0 : rest.className}` }));
|
|
90
|
-
},
|
|
91
|
-
p: (props) => {
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
93
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
94
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.p }, rest, { isPrimary: isPrimary }));
|
|
95
|
-
},
|
|
96
|
-
code: (_a) => {
|
|
97
|
-
var { children } = _a, props = __rest(_a, ["children"]);
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
-
const { node } = props, codeProps = __rest(props, ["node"]);
|
|
100
|
-
return (_jsx(CodeBlockMessage, Object.assign({}, codeProps, codeBlockProps, { isPrimary: isPrimary, children: children })));
|
|
101
|
-
},
|
|
102
|
-
h1: (props) => {
|
|
103
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
104
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
105
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h1 }, rest));
|
|
106
|
-
},
|
|
107
|
-
h2: (props) => {
|
|
108
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
109
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
110
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h2 }, rest));
|
|
111
|
-
},
|
|
112
|
-
h3: (props) => {
|
|
113
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
114
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
115
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h3 }, rest));
|
|
116
|
-
},
|
|
117
|
-
h4: (props) => {
|
|
118
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
119
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
120
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h4 }, rest));
|
|
121
|
-
},
|
|
122
|
-
h5: (props) => {
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
124
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
125
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h5 }, rest));
|
|
126
|
-
},
|
|
127
|
-
h6: (props) => {
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
129
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
130
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.h6 }, rest));
|
|
131
|
-
},
|
|
132
|
-
blockquote: (props) => {
|
|
133
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
134
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
135
|
-
return _jsx(TextMessage, Object.assign({ component: ContentVariants.blockquote }, rest));
|
|
136
|
-
},
|
|
137
|
-
ul: (props) => {
|
|
138
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
139
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
140
|
-
return _jsx(UnorderedListMessage, Object.assign({}, rest));
|
|
141
|
-
},
|
|
142
|
-
ol: (props) => {
|
|
143
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
144
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
145
|
-
return _jsx(OrderedListMessage, Object.assign({}, rest));
|
|
146
|
-
},
|
|
147
|
-
li: (props) => {
|
|
148
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
149
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
150
|
-
return _jsx(ListItemMessage, Object.assign({}, rest));
|
|
151
|
-
},
|
|
152
|
-
// table requires node attribute for calculating headers for mobile breakpoint
|
|
153
|
-
table: (props) => _jsx(TableMessage, Object.assign({}, props, tableProps, { isPrimary: isPrimary })),
|
|
154
|
-
tbody: (props) => {
|
|
155
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
156
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
157
|
-
return _jsx(TbodyMessage, Object.assign({}, rest));
|
|
158
|
-
},
|
|
159
|
-
thead: (props) => {
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
161
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
162
|
-
return _jsx(TheadMessage, Object.assign({}, rest));
|
|
163
|
-
},
|
|
164
|
-
tr: (props) => {
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
166
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
167
|
-
return _jsx(TrMessage, Object.assign({}, rest));
|
|
168
|
-
},
|
|
169
|
-
td: (props) => {
|
|
170
|
-
// Conflicts with Td type
|
|
171
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
172
|
-
const { node, width } = props, rest = __rest(props, ["node", "width"]);
|
|
173
|
-
return _jsx(TdMessage, Object.assign({}, rest));
|
|
174
|
-
},
|
|
175
|
-
th: (props) => {
|
|
176
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
177
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
178
|
-
return _jsx(ThMessage, Object.assign({}, rest));
|
|
179
|
-
},
|
|
180
|
-
img: (props) => {
|
|
181
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
182
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
183
|
-
return _jsx(ImageMessage, Object.assign({}, rest));
|
|
184
|
-
},
|
|
185
|
-
a: (props) => {
|
|
186
|
-
// node is just the details of the document structure - not needed
|
|
187
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
188
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
189
|
-
return (
|
|
190
|
-
// some a types conflict with ButtonProps, but it's ok because we are using an a tag
|
|
191
|
-
// there are too many to handle manually
|
|
192
|
-
_jsx(LinkMessage, Object.assign({}, rest, linkProps, { children: props.children })));
|
|
193
|
-
},
|
|
194
|
-
// used for footnotes
|
|
195
|
-
sup: (props) => {
|
|
196
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
197
|
-
const { node } = props, rest = __rest(props, ["node"]);
|
|
198
|
-
return _jsx(SuperscriptMessage, Object.assign({}, rest));
|
|
199
|
-
}
|
|
200
|
-
}, remarkPlugins: [[remarkGfm, Object.assign({}, remarkGfmProps)], ...additionalRemarkPlugins], rehypePlugins: rehypePlugins }, reactMarkdownProps, { remarkRehypeOptions: Object.assign({
|
|
201
|
-
// removes sr-only class from footnote labels applied by default
|
|
202
|
-
footnoteLabelProperties: { className: [''] } }, reactMarkdownProps === null || reactMarkdownProps === void 0 ? void 0 : reactMarkdownProps.remarkRehypeOptions), disallowedElements: disallowedElements, children: messageText })));
|
|
203
|
-
};
|
|
50
|
+
const handleMarkdown = () => (_jsx(MarkdownContent, { content: messageText, isMarkdownDisabled: isMarkdownDisabled, codeBlockProps: codeBlockProps, tableProps: tableProps, openLinkInNewTab: openLinkInNewTab, additionalRehypePlugins: additionalRehypePlugins, additionalRemarkPlugins: additionalRemarkPlugins, linkProps: linkProps, reactMarkdownProps: reactMarkdownProps, remarkGfmProps: remarkGfmProps, hasNoImages: role === 'user' && hasNoImagesInUserMessages, isPrimary: isPrimary }));
|
|
204
51
|
const renderMessage = () => {
|
|
205
52
|
if (isLoading) {
|
|
206
53
|
return _jsx(MessageLoading, { loadingWord: loadingWord, isPrimary: isPrimary });
|
|
@@ -16,7 +16,12 @@ export interface TableNode {
|
|
|
16
16
|
type: string;
|
|
17
17
|
}
|
|
18
18
|
export interface TableMessageProps {
|
|
19
|
+
/** Content of the table */
|
|
20
|
+
children?: React.ReactNode;
|
|
21
|
+
/** Flag indicating whether primary styles should be applied. */
|
|
19
22
|
isPrimary?: boolean;
|
|
23
|
+
/** Flag indicating that the content should retain message styles when using Markdown. */
|
|
24
|
+
shouldRetainStyles?: boolean;
|
|
20
25
|
}
|
|
21
|
-
declare const TableMessage: ({ children, isPrimary, ...props }: Omit<TableProps, "ref"> & ExtraProps & TableMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
declare const TableMessage: ({ children, isPrimary, shouldRetainStyles, ...props }: Omit<TableProps, "ref"> & ExtraProps & TableMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
22
27
|
export default TableMessage;
|
|
@@ -15,9 +15,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
15
15
|
// ============================================================================
|
|
16
16
|
import { Children, cloneElement } from 'react';
|
|
17
17
|
import { Table } from '@patternfly/react-table';
|
|
18
|
+
import { css } from '@patternfly/react-styles';
|
|
18
19
|
const TableMessage = (_a) => {
|
|
19
20
|
var _b;
|
|
20
|
-
var { children, isPrimary } = _a, props = __rest(_a, ["children", "isPrimary"]);
|
|
21
|
+
var { children, isPrimary, shouldRetainStyles } = _a, props = __rest(_a, ["children", "isPrimary", "shouldRetainStyles"]);
|
|
21
22
|
const { className } = props, rest = __rest(props, ["className"]);
|
|
22
23
|
// This allows us to parse the nested data we get back from the 3rd party Markdown parser
|
|
23
24
|
// Open to feedback here if there is a better way to do this
|
|
@@ -58,6 +59,6 @@ const TableMessage = (_a) => {
|
|
|
58
59
|
}
|
|
59
60
|
return (
|
|
60
61
|
// gridBreakPoint is so we show mobile-styled-PF table
|
|
61
|
-
_jsx(Table, Object.assign({ "aria-label": props['aria-label'], gridBreakPoint: "grid", className:
|
|
62
|
+
_jsx(Table, Object.assign({ "aria-label": props['aria-label'], gridBreakPoint: "grid", className: css('pf-chatbot__message-table', isPrimary && 'pf-m-primary', shouldRetainStyles && 'pf-m-markdown', className) }, rest, { children: modifyChildren(children) })));
|
|
62
63
|
};
|
|
63
64
|
export default TableMessage;
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { ExtraProps } from 'react-markdown';
|
|
2
2
|
import { ContentProps } from '@patternfly/react-core';
|
|
3
3
|
export interface TextMessageProps {
|
|
4
|
+
/** The text message content */
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
/** Flag indicating whether primary styling is applied. */
|
|
4
7
|
isPrimary?: boolean;
|
|
8
|
+
/** The wrapper component to use for the PatternFly Content component. Defaults to a div. */
|
|
9
|
+
component?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'a' | 'small' | 'blockquote' | 'pre' | 'hr' | 'ul' | 'ol' | 'dl' | 'li' | 'dt' | 'dd';
|
|
10
|
+
/** Flag indicating that the content should retain message styles when using Markdown. */
|
|
11
|
+
shouldRetainStyles?: boolean;
|
|
5
12
|
}
|
|
6
|
-
declare const TextMessage: ({ component, children, isPrimary, ...props }: Omit<ContentProps, "ref"> & ExtraProps & TextMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare const TextMessage: ({ component, children, isPrimary, shouldRetainStyles, ...props }: Omit<ContentProps, "ref"> & ExtraProps & TextMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
14
|
export default TextMessage;
|
|
@@ -11,8 +11,9 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
import { Content } from '@patternfly/react-core';
|
|
14
|
+
import { css } from '@patternfly/react-styles';
|
|
14
15
|
const TextMessage = (_a) => {
|
|
15
|
-
var { component, children, isPrimary } = _a, props = __rest(_a, ["component", "children", "isPrimary"]);
|
|
16
|
-
return (_jsx("span", { className:
|
|
16
|
+
var { component, children, isPrimary, shouldRetainStyles } = _a, props = __rest(_a, ["component", "children", "isPrimary", "shouldRetainStyles"]);
|
|
17
|
+
return (_jsx("span", { className: css('pf-chatbot__message-text', isPrimary && 'pf-m-primary', shouldRetainStyles && 'pf-m-markdown'), children: _jsx(Content, Object.assign({ component: component }, props, { className: css(props === null || props === void 0 ? void 0 : props.className), children: children })) }));
|
|
17
18
|
};
|
|
18
19
|
export default TextMessage;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FunctionComponent } from 'react';
|
|
2
2
|
import { ActionListProps, ActionListGroupProps, ActionListItemProps, ButtonProps, CardProps, CardBodyProps, CardFooterProps, ExpandableSectionProps, SpinnerProps } from '@patternfly/react-core';
|
|
3
|
+
import type { MarkdownContentProps } from '../MarkdownContent';
|
|
3
4
|
export interface ToolCallProps {
|
|
4
5
|
/** Title text for the tool call. */
|
|
5
6
|
titleText: string;
|
|
@@ -11,6 +12,8 @@ export interface ToolCallProps {
|
|
|
11
12
|
spinnerProps?: SpinnerProps;
|
|
12
13
|
/** Content to render within an expandable section. */
|
|
13
14
|
expandableContent?: React.ReactNode;
|
|
15
|
+
/** Flag indicating whether the expandable content is expanded by default. */
|
|
16
|
+
isDefaultExpanded?: boolean;
|
|
14
17
|
/** Text content for the "run" action button. */
|
|
15
18
|
runButtonText?: string;
|
|
16
19
|
/** Additional props for the "run" action button. */
|
|
@@ -39,6 +42,14 @@ export interface ToolCallProps {
|
|
|
39
42
|
cardFooterProps?: CardFooterProps;
|
|
40
43
|
/** Additional props for the expandable section when expandableContent is passed. */
|
|
41
44
|
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
|
|
45
|
+
/** Whether to enable markdown rendering for titleText. When true, titleText will be parsed as markdown. */
|
|
46
|
+
isTitleMarkdown?: boolean;
|
|
47
|
+
/** Whether to enable markdown rendering for expandableContent. When true and expandableContent is a string, it will be parsed as markdown. */
|
|
48
|
+
isExpandableContentMarkdown?: boolean;
|
|
49
|
+
/** Props passed to MarkdownContent component when markdown is enabled */
|
|
50
|
+
markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
|
|
51
|
+
/** Whether to retain styles in the MarkdownContent component. Defaults to false. */
|
|
52
|
+
shouldRetainStyles?: boolean;
|
|
42
53
|
}
|
|
43
54
|
export declare const ToolCall: FunctionComponent<ToolCallProps>;
|
|
44
55
|
export default ToolCall;
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { ActionList, ActionListGroup, ActionListItem, Button, Card, CardBody, CardFooter, ExpandableSection, Spinner } from '@patternfly/react-core';
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import MarkdownContent from '../MarkdownContent';
|
|
5
|
+
export const ToolCall = ({ titleText, loadingText, isLoading, expandableContent, isDefaultExpanded = false, runButtonText = 'Run tool', runButtonProps, runActionItemProps, cancelButtonText = 'Cancel', cancelButtonProps, cancelActionItemProps, actions, actionListProps, actionListGroupProps, actionListItemProps, cardProps, cardBodyProps, cardFooterProps, expandableSectionProps, spinnerProps, isTitleMarkdown, isExpandableContentMarkdown, markdownContentProps, shouldRetainStyles = false }) => {
|
|
6
|
+
const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
|
|
7
|
+
const onToggle = (_event, isExpanded) => {
|
|
8
|
+
setIsExpanded(isExpanded);
|
|
9
|
+
};
|
|
10
|
+
const renderTitle = () => {
|
|
11
|
+
if (isTitleMarkdown) {
|
|
12
|
+
return _jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: titleText }, markdownContentProps));
|
|
13
|
+
}
|
|
14
|
+
return titleText;
|
|
15
|
+
};
|
|
16
|
+
const titleContent = (_jsx("span", { className: `pf-chatbot__tool-call-title-content`, children: isLoading ? (_jsxs(_Fragment, { children: [_jsx(Spinner, Object.assign({ diameter: "1em" }, spinnerProps)), ' ', _jsx("span", { className: "pf-chatbot__tool-call-title-text", children: loadingText })] })) : (_jsx("span", { className: "pf-chatbot__tool-call-title-text", children: renderTitle() })) }));
|
|
17
|
+
const renderExpandableContent = () => {
|
|
18
|
+
if (isExpandableContentMarkdown && typeof expandableContent === 'string') {
|
|
19
|
+
return (_jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: expandableContent }, markdownContentProps)));
|
|
20
|
+
}
|
|
21
|
+
return expandableContent;
|
|
22
|
+
};
|
|
5
23
|
const defaultActions = (_jsxs(_Fragment, { children: [_jsx(ActionListItem, Object.assign({}, actionListItemProps, cancelActionItemProps, { children: _jsx(Button, Object.assign({ variant: "link" }, cancelButtonProps, { children: cancelButtonText })) })), _jsx(ActionListItem, Object.assign({}, actionListItemProps, runActionItemProps, { children: _jsx(Button, Object.assign({ variant: "secondary" }, runButtonProps, { children: runButtonText })) }))] }));
|
|
6
24
|
const customActions = actions &&
|
|
7
25
|
actions.map((action, index) => (_jsx(ActionListItem, Object.assign({}, actionListItemProps, { children: action }), index)));
|
|
8
|
-
return (_jsxs(Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-call" }, cardProps, { children: [_jsx(CardBody, Object.assign({ className: "pf-chatbot__tool-call-title" }, cardBodyProps, { children: expandableContent && !isLoading ? (_jsx(ExpandableSection, Object.assign({ className: "pf-chatbot__tool-call-expandable-section", toggleContent: titleContent, isIndented: true }, expandableSectionProps, { children:
|
|
26
|
+
return (_jsxs(Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-call" }, cardProps, { children: [_jsx(CardBody, Object.assign({ className: "pf-chatbot__tool-call-title" }, cardBodyProps, { children: expandableContent && !isLoading ? (_jsx(ExpandableSection, Object.assign({ className: "pf-chatbot__tool-call-expandable-section", toggleContent: titleContent, onToggle: onToggle, isExpanded: isExpanded, isIndented: true }, expandableSectionProps, { children: renderExpandableContent() }))) : (titleContent) })), !isLoading && (_jsx(CardFooter, Object.assign({}, cardFooterProps, { children: _jsx(ActionList, Object.assign({ className: "pf-chatbot__tool-call-action-list" }, actionListProps, { children: _jsx(ActionListGroup, Object.assign({}, actionListGroupProps, { children: customActions || defaultActions })) })) })))] })));
|
|
9
27
|
};
|
|
10
28
|
export default ToolCall;
|
|
@@ -136,4 +136,61 @@ describe('ToolCall', () => {
|
|
|
136
136
|
render(_jsx(ToolCall, Object.assign({}, defaultProps, { cardFooterProps: { id: 'card-footer-test-id' } })));
|
|
137
137
|
expect(screen.getByRole('button', { name: 'Run tool' }).closest('#card-footer-test-id')).toBeVisible();
|
|
138
138
|
});
|
|
139
|
+
it('Renders collapsed by default when expandableContent is provided', () => {
|
|
140
|
+
render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: "Expandable Content" })));
|
|
141
|
+
expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'false');
|
|
142
|
+
expect(screen.queryByText('Expandable Content')).not.toBeVisible();
|
|
143
|
+
});
|
|
144
|
+
it('Renders expanded when isDefaultExpanded is true', () => {
|
|
145
|
+
render(_jsx(ToolCall, Object.assign({}, defaultProps, { isDefaultExpanded: true, expandableContent: "Expandable Content" })));
|
|
146
|
+
expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'true');
|
|
147
|
+
expect(screen.getByText('Expandable Content')).toBeVisible();
|
|
148
|
+
});
|
|
149
|
+
it('expandableSectionProps.isExpanded overrides isDefaultExpanded', () => {
|
|
150
|
+
render(_jsx(ToolCall, Object.assign({}, defaultProps, { isDefaultExpanded: false, expandableContent: "Expandable Content", expandableSectionProps: { isExpanded: true } })));
|
|
151
|
+
expect(screen.getByRole('button', { name: defaultProps.titleText })).toHaveAttribute('aria-expanded', 'true');
|
|
152
|
+
expect(screen.getByText('Expandable Content')).toBeVisible();
|
|
153
|
+
});
|
|
154
|
+
it('expandableSectionProps.onToggle overrides internal onToggle behavior', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
155
|
+
const user = userEvent.setup();
|
|
156
|
+
const customOnToggle = jest.fn();
|
|
157
|
+
render(_jsx(ToolCall, Object.assign({}, defaultProps, { isDefaultExpanded: false, expandableContent: "Expandable Content", expandableSectionProps: { onToggle: customOnToggle } })));
|
|
158
|
+
const toggleButton = screen.getByRole('button', { name: defaultProps.titleText });
|
|
159
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
160
|
+
yield user.click(toggleButton);
|
|
161
|
+
expect(customOnToggle).toHaveBeenCalledTimes(1);
|
|
162
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
163
|
+
expect(screen.queryByText('Expandable Content')).not.toBeVisible();
|
|
164
|
+
}));
|
|
165
|
+
it('should render titleText as markdown when isTitleMarkdown is true', () => {
|
|
166
|
+
const titleText = '**Bold title**';
|
|
167
|
+
const { container } = render(_jsx(ToolCall, { titleText: titleText, isTitleMarkdown: true }));
|
|
168
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
169
|
+
expect(screen.getByText('Bold title')).toBeTruthy();
|
|
170
|
+
});
|
|
171
|
+
it('should not render titleText as markdown when isTitleMarkdown is false', () => {
|
|
172
|
+
const titleText = '**Bold title**';
|
|
173
|
+
render(_jsx(ToolCall, { titleText: titleText }));
|
|
174
|
+
expect(screen.getByText('**Bold title**')).toBeTruthy();
|
|
175
|
+
});
|
|
176
|
+
it('should render expandableContent as markdown when isExpandableContentMarkdown is true', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
177
|
+
const user = userEvent.setup();
|
|
178
|
+
const expandableContent = '**Bold expandable content**';
|
|
179
|
+
const { container } = render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: expandableContent, isExpandableContentMarkdown: true })));
|
|
180
|
+
yield user.click(screen.getByRole('button', { name: defaultProps.titleText }));
|
|
181
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
182
|
+
expect(screen.getByText('Bold expandable content')).toBeTruthy();
|
|
183
|
+
}));
|
|
184
|
+
it('should not render expandableContent as markdown when isExpandableContentMarkdown is false', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
185
|
+
const user = userEvent.setup();
|
|
186
|
+
const expandableContent = '**Bold expandable content**';
|
|
187
|
+
render(_jsx(ToolCall, Object.assign({}, defaultProps, { expandableContent: expandableContent })));
|
|
188
|
+
yield user.click(screen.getByRole('button', { name: defaultProps.titleText }));
|
|
189
|
+
expect(screen.getByText('**Bold expandable content**')).toBeTruthy();
|
|
190
|
+
}));
|
|
191
|
+
it('should pass markdownContentProps to MarkdownContent component', () => {
|
|
192
|
+
const titleText = '**Bold title**';
|
|
193
|
+
const { container } = render(_jsx(ToolCall, { titleText: titleText, isTitleMarkdown: true, markdownContentProps: { isPrimary: true } }));
|
|
194
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
195
|
+
});
|
|
139
196
|
});
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CardBodyProps, CardProps, CardTitleProps, DividerProps, ExpandableSectionProps } from '@patternfly/react-core';
|
|
2
2
|
import { type FunctionComponent } from 'react';
|
|
3
|
+
import type { MarkdownContentProps } from '../MarkdownContent';
|
|
3
4
|
export interface ToolResponseProps {
|
|
4
5
|
/** Toggle content shown for expandable section */
|
|
5
6
|
toggleContent: React.ReactNode;
|
|
7
|
+
/** Flag indicating whether the expandable content is expanded by default. */
|
|
8
|
+
isDefaultExpanded?: boolean;
|
|
6
9
|
/** Additional props passed to expandable section */
|
|
7
10
|
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
|
|
8
11
|
/** Subheading rendered inside expandable section */
|
|
@@ -25,6 +28,20 @@ export interface ToolResponseProps {
|
|
|
25
28
|
toolResponseCardDividerProps?: DividerProps;
|
|
26
29
|
/** Additional props passed to tool response card title */
|
|
27
30
|
toolResponseCardTitleProps?: CardTitleProps;
|
|
31
|
+
/** Whether to enable markdown rendering for toggleContent. When true and toggleContent is a string, it will be parsed as markdown. */
|
|
32
|
+
isToggleContentMarkdown?: boolean;
|
|
33
|
+
/** Whether to enable markdown rendering for subheading. When true, subheading will be parsed as markdown. */
|
|
34
|
+
isSubheadingMarkdown?: boolean;
|
|
35
|
+
/** Whether to enable markdown rendering for body. When true and body is a string, it will be parsed as markdown. */
|
|
36
|
+
isBodyMarkdown?: boolean;
|
|
37
|
+
/** Whether to enable markdown rendering for cardBody. When true and cardBody is a string, it will be parsed as markdown. */
|
|
38
|
+
isCardBodyMarkdown?: boolean;
|
|
39
|
+
/** Whether to enable markdown rendering for cardTitle. When true and cardTitle is a string, it will be parsed as markdown. */
|
|
40
|
+
isCardTitleMarkdown?: boolean;
|
|
41
|
+
/** Props passed to MarkdownContent component when markdown is enabled */
|
|
42
|
+
markdownContentProps?: Omit<MarkdownContentProps, 'content'>;
|
|
43
|
+
/** Whether to retain styles in the MarkdownContent component. Defaults to false. */
|
|
44
|
+
shouldRetainStyles?: boolean;
|
|
28
45
|
}
|
|
29
46
|
export declare const ToolResponse: FunctionComponent<ToolResponseProps>;
|
|
30
47
|
export default ToolResponse;
|
|
@@ -4,11 +4,54 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
// ============================================================================
|
|
5
5
|
import { Card, CardBody, CardTitle, Divider, ExpandableSection } from '@patternfly/react-core';
|
|
6
6
|
import { useState } from 'react';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import MarkdownContent from '../MarkdownContent';
|
|
8
|
+
export const ToolResponse = ({ body, cardProps, expandableSectionProps, subheading, cardBody, cardTitle, cardBodyProps, toggleContent, isDefaultExpanded = true, toolResponseCardBodyProps, toolResponseCardDividerProps, toolResponseCardProps, toolResponseCardTitleProps, isToggleContentMarkdown, isSubheadingMarkdown, isBodyMarkdown, isCardBodyMarkdown, isCardTitleMarkdown, markdownContentProps, shouldRetainStyles = false }) => {
|
|
9
|
+
const [isExpanded, setIsExpanded] = useState(isDefaultExpanded);
|
|
9
10
|
const onToggle = (_event, isExpanded) => {
|
|
10
11
|
setIsExpanded(isExpanded);
|
|
11
12
|
};
|
|
12
|
-
|
|
13
|
+
const renderToggleContent = () => {
|
|
14
|
+
if (isToggleContentMarkdown && typeof toggleContent === 'string') {
|
|
15
|
+
return (_jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: toggleContent }, markdownContentProps)));
|
|
16
|
+
}
|
|
17
|
+
return toggleContent;
|
|
18
|
+
};
|
|
19
|
+
const renderSubheading = () => {
|
|
20
|
+
if (!subheading) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (isSubheadingMarkdown) {
|
|
24
|
+
return _jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: subheading }, markdownContentProps));
|
|
25
|
+
}
|
|
26
|
+
return subheading;
|
|
27
|
+
};
|
|
28
|
+
const renderBody = () => {
|
|
29
|
+
if (!body) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (isBodyMarkdown && typeof body === 'string') {
|
|
33
|
+
return _jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: body }, markdownContentProps));
|
|
34
|
+
}
|
|
35
|
+
return body;
|
|
36
|
+
};
|
|
37
|
+
const renderCardTitle = () => {
|
|
38
|
+
if (!cardTitle) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
if (isCardTitleMarkdown && typeof cardTitle === 'string') {
|
|
42
|
+
return _jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: cardTitle }, markdownContentProps));
|
|
43
|
+
}
|
|
44
|
+
return cardTitle;
|
|
45
|
+
};
|
|
46
|
+
const renderCardBody = () => {
|
|
47
|
+
if (!cardBody) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (isCardBodyMarkdown && typeof cardBody === 'string') {
|
|
51
|
+
return _jsx(MarkdownContent, Object.assign({ shouldRetainStyles: shouldRetainStyles, content: cardBody }, markdownContentProps));
|
|
52
|
+
}
|
|
53
|
+
return cardBody;
|
|
54
|
+
};
|
|
55
|
+
return (_jsx(Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-response" }, cardProps, { children: _jsx(CardBody, Object.assign({}, cardBodyProps, { children: _jsx(ExpandableSection, Object.assign({ toggleContent: renderToggleContent(), onToggle: onToggle, isExpanded: isExpanded, isIndented: true, className: "pf-chatbot__tool-response-expandable-section" }, expandableSectionProps, { children: _jsxs("div", { className: "pf-chatbot__tool-response-section", children: [subheading && (_jsx("div", { className: "pf-chatbot__tool-response-subheading", children: _jsx("span", { children: renderSubheading() }) })), body && _jsx("div", { className: "pf-chatbot__tool-response-body", children: renderBody() }), (cardTitle || cardBody) && (_jsxs(Card, Object.assign({ isCompact: true, className: "pf-chatbot__tool-response-card" }, toolResponseCardProps, { children: [cardTitle && _jsx(CardTitle, Object.assign({}, toolResponseCardTitleProps, { children: renderCardTitle() })), cardTitle && cardBody && _jsx(Divider, Object.assign({}, toolResponseCardDividerProps)), cardBody && _jsx(CardBody, Object.assign({}, toolResponseCardBodyProps, { children: renderCardBody() }))] })))] }) })) })) })));
|
|
13
56
|
};
|
|
14
57
|
export default ToolResponse;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
1
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
11
|
import { render, screen } from '@testing-library/react';
|
|
12
|
+
import userEvent from '@testing-library/user-event';
|
|
3
13
|
import '@testing-library/jest-dom';
|
|
4
14
|
import ToolResponse from './ToolResponse';
|
|
5
15
|
describe('ToolResponse', () => {
|
|
@@ -76,4 +86,94 @@ describe('ToolResponse', () => {
|
|
|
76
86
|
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { cardBody: undefined })));
|
|
77
87
|
expect(container.querySelector('.pf-v6-c-divider')).toBeFalsy();
|
|
78
88
|
});
|
|
89
|
+
it('Renders expanded by default', () => {
|
|
90
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps)));
|
|
91
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
|
|
92
|
+
expect(screen.getByText(defaultProps.cardTitle)).toBeVisible();
|
|
93
|
+
expect(screen.getByText(defaultProps.cardBody)).toBeVisible();
|
|
94
|
+
});
|
|
95
|
+
it('Renders collapsed when isDefaultExpanded is false', () => {
|
|
96
|
+
render(_jsx(ToolResponse, Object.assign({ isDefaultExpanded: false }, defaultProps)));
|
|
97
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'false');
|
|
98
|
+
expect(screen.getByText(defaultProps.cardTitle)).not.toBeVisible();
|
|
99
|
+
expect(screen.getByText(defaultProps.cardBody)).not.toBeVisible();
|
|
100
|
+
});
|
|
101
|
+
it('expandableSectionProps.isExpanded overrides isDefaultExpanded', () => {
|
|
102
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { isDefaultExpanded: false, expandableSectionProps: { isExpanded: true } })));
|
|
103
|
+
expect(screen.getByRole('button', { name: defaultProps.toggleContent })).toHaveAttribute('aria-expanded', 'true');
|
|
104
|
+
expect(screen.getByText(defaultProps.cardTitle)).toBeVisible();
|
|
105
|
+
expect(screen.getByText(defaultProps.cardBody)).toBeVisible();
|
|
106
|
+
});
|
|
107
|
+
it('expandableSectionProps.onToggle overrides internal onToggle behavior', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
108
|
+
const user = userEvent.setup();
|
|
109
|
+
const customOnToggle = jest.fn();
|
|
110
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { isDefaultExpanded: false, expandableSectionProps: { onToggle: customOnToggle } })));
|
|
111
|
+
const toggleButton = screen.getByRole('button', { name: defaultProps.toggleContent });
|
|
112
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
113
|
+
yield user.click(toggleButton);
|
|
114
|
+
expect(customOnToggle).toHaveBeenCalledTimes(1);
|
|
115
|
+
expect(toggleButton).toHaveAttribute('aria-expanded', 'false');
|
|
116
|
+
expect(screen.getByText(defaultProps.cardTitle)).not.toBeVisible();
|
|
117
|
+
expect(screen.getByText(defaultProps.cardBody)).not.toBeVisible();
|
|
118
|
+
}));
|
|
119
|
+
it('should render toggleContent as markdown when isToggleContentMarkdown is true', () => {
|
|
120
|
+
const toggleContent = '**Bold toggle**';
|
|
121
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { toggleContent: toggleContent, isToggleContentMarkdown: true })));
|
|
122
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
123
|
+
expect(screen.getByText('Bold toggle')).toBeTruthy();
|
|
124
|
+
});
|
|
125
|
+
it('should not render toggleContent as markdown when isToggleContentMarkdown is false', () => {
|
|
126
|
+
const toggleContent = '**Bold toggle**';
|
|
127
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { toggleContent: toggleContent })));
|
|
128
|
+
expect(screen.getByText('**Bold toggle**')).toBeTruthy();
|
|
129
|
+
});
|
|
130
|
+
it('should render subheading as markdown when isSubheadingMarkdown is true', () => {
|
|
131
|
+
const subheading = '**Bold subheading**';
|
|
132
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { subheading: subheading, isSubheadingMarkdown: true })));
|
|
133
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
134
|
+
expect(screen.getByText('Bold subheading')).toBeTruthy();
|
|
135
|
+
});
|
|
136
|
+
it('should not render subheading as markdown when isSubheadingMarkdown is false', () => {
|
|
137
|
+
const subheading = '**Bold subheading**';
|
|
138
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { subheading: subheading })));
|
|
139
|
+
expect(screen.getByText('**Bold subheading**')).toBeTruthy();
|
|
140
|
+
});
|
|
141
|
+
it('should render body as markdown when isBodyMarkdown is true', () => {
|
|
142
|
+
const body = '**Bold body**';
|
|
143
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { body: body, isBodyMarkdown: true })));
|
|
144
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
145
|
+
expect(screen.getByText('Bold body')).toBeTruthy();
|
|
146
|
+
});
|
|
147
|
+
it('should not render body as markdown when isBodyMarkdown is false', () => {
|
|
148
|
+
const body = '**Bold body**';
|
|
149
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { body: body })));
|
|
150
|
+
expect(screen.getByText('**Bold body**')).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
it('should render cardTitle as markdown when isCardTitleMarkdown is true', () => {
|
|
153
|
+
const cardTitle = '**Bold card title**';
|
|
154
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { cardTitle: cardTitle, isCardTitleMarkdown: true })));
|
|
155
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
156
|
+
expect(screen.getByText('Bold card title')).toBeTruthy();
|
|
157
|
+
});
|
|
158
|
+
it('should not render cardTitle as markdown when isCardTitleMarkdown is false', () => {
|
|
159
|
+
const cardTitle = '**Bold card title**';
|
|
160
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { cardTitle: cardTitle })));
|
|
161
|
+
expect(screen.getByText('**Bold card title**')).toBeTruthy();
|
|
162
|
+
});
|
|
163
|
+
it('should render cardBody as markdown when isCardBodyMarkdown is true', () => {
|
|
164
|
+
const cardBody = '**Bold card body**';
|
|
165
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { cardBody: cardBody, isCardBodyMarkdown: true })));
|
|
166
|
+
expect(container.querySelector('strong')).toBeTruthy();
|
|
167
|
+
expect(screen.getByText('Bold card body')).toBeTruthy();
|
|
168
|
+
});
|
|
169
|
+
it('should not render cardBody as markdown when isCardBodyMarkdown is false', () => {
|
|
170
|
+
const cardBody = '**Bold card body**';
|
|
171
|
+
render(_jsx(ToolResponse, Object.assign({}, defaultProps, { cardBody: cardBody })));
|
|
172
|
+
expect(screen.getByText('**Bold card body**')).toBeTruthy();
|
|
173
|
+
});
|
|
174
|
+
it('should pass markdownContentProps to MarkdownContent component', () => {
|
|
175
|
+
const body = '**Bold body**';
|
|
176
|
+
const { container } = render(_jsx(ToolResponse, Object.assign({}, defaultProps, { body: body, isBodyMarkdown: true, markdownContentProps: { isPrimary: true } })));
|
|
177
|
+
expect(container.querySelector('.pf-m-primary')).toBeTruthy();
|
|
178
|
+
});
|
|
79
179
|
});
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export { default as ImagePreview } from './ImagePreview';
|
|
|
40
40
|
export * from './ImagePreview';
|
|
41
41
|
export { default as LoadingMessage } from './LoadingMessage';
|
|
42
42
|
export * from './LoadingMessage';
|
|
43
|
+
export { default as MarkdownContent } from './MarkdownContent';
|
|
44
|
+
export * from './MarkdownContent';
|
|
43
45
|
export { default as Message } from './Message';
|
|
44
46
|
export * from './Message';
|
|
45
47
|
export { default as MessageBar } from './MessageBar';
|
package/dist/esm/index.js
CHANGED
|
@@ -41,6 +41,8 @@ export { default as ImagePreview } from './ImagePreview';
|
|
|
41
41
|
export * from './ImagePreview';
|
|
42
42
|
export { default as LoadingMessage } from './LoadingMessage';
|
|
43
43
|
export * from './LoadingMessage';
|
|
44
|
+
export { default as MarkdownContent } from './MarkdownContent';
|
|
45
|
+
export * from './MarkdownContent';
|
|
44
46
|
export { default as Message } from './Message';
|
|
45
47
|
export * from './Message';
|
|
46
48
|
export { default as MessageBar } from './MessageBar';
|