@patternfly/chatbot 6.3.0-prerelease.17 → 6.3.0-prerelease.18
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/Message/CodeBlockMessage/CodeBlockMessage.d.ts +20 -2
- package/dist/cjs/Message/CodeBlockMessage/CodeBlockMessage.js +14 -3
- package/dist/cjs/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.d.ts +62 -0
- package/dist/cjs/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.js +136 -0
- package/dist/cjs/Message/Message.d.ts +16 -1
- package/dist/cjs/Message/Message.test.js +24 -0
- package/dist/css/main.css +10 -0
- package/dist/css/main.css.map +1 -1
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.d.ts +20 -2
- package/dist/esm/Message/CodeBlockMessage/CodeBlockMessage.js +15 -4
- package/dist/esm/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.d.ts +62 -0
- package/dist/esm/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.js +130 -0
- package/dist/esm/Message/Message.d.ts +16 -1
- package/dist/esm/Message/Message.test.js +24 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/design-guidelines.md +10 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Customizing Messages/Customizing Messages.md +51 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +9 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +9 -0
- package/patternfly-docs/content/extensions/chatbot/img/quick-response-confirmation.svg +67 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.scss +7 -0
- package/src/Message/CodeBlockMessage/CodeBlockMessage.tsx +99 -12
- package/src/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.tsx +220 -0
- package/src/Message/Message.test.tsx +30 -0
- package/src/Message/Message.tsx +17 -0
@@ -0,0 +1,130 @@
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
2
|
+
var t = {};
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
4
|
+
t[p] = s[p];
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
8
|
+
t[p[i]] = s[p[i]];
|
9
|
+
}
|
10
|
+
return t;
|
11
|
+
};
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
13
|
+
import { Component, createRef } from 'react';
|
14
|
+
import styles from '@patternfly/react-styles/css/components/ExpandableSection/expandable-section';
|
15
|
+
import { css } from '@patternfly/react-styles';
|
16
|
+
import lineClamp from '@patternfly/react-tokens/dist/esm/c_expandable_section_m_truncate__content_LineClamp';
|
17
|
+
import { debounce, getResizeObserver, getUniqueId } from '@patternfly/react-core';
|
18
|
+
export var ExpandableSectionVariant;
|
19
|
+
(function (ExpandableSectionVariant) {
|
20
|
+
ExpandableSectionVariant["default"] = "default";
|
21
|
+
ExpandableSectionVariant["truncate"] = "truncate";
|
22
|
+
})(ExpandableSectionVariant || (ExpandableSectionVariant = {}));
|
23
|
+
const setLineClamp = (element, lines, language, isExpanded) => {
|
24
|
+
if (!element || !lines || lines < 1 || typeof isExpanded === 'undefined') {
|
25
|
+
return;
|
26
|
+
}
|
27
|
+
if (language) {
|
28
|
+
const selector = `.language-${language.toLowerCase()}`;
|
29
|
+
const childElement = element.querySelector(selector);
|
30
|
+
if (!childElement) {
|
31
|
+
return;
|
32
|
+
}
|
33
|
+
if (isExpanded) {
|
34
|
+
// Reset all truncation-related styles to their default values
|
35
|
+
childElement.style.removeProperty('-webkit-line-clamp');
|
36
|
+
childElement.style.removeProperty('display');
|
37
|
+
childElement.style.removeProperty('-webkit-box-orient');
|
38
|
+
childElement.style.removeProperty('overflow');
|
39
|
+
}
|
40
|
+
else {
|
41
|
+
childElement.style.setProperty('-webkit-line-clamp', lines.toString());
|
42
|
+
childElement.style.setProperty('display', '-webkit-box');
|
43
|
+
childElement.style.setProperty('-webkit-box-orient', 'vertical');
|
44
|
+
childElement.style.setProperty('overflow', 'hidden');
|
45
|
+
}
|
46
|
+
}
|
47
|
+
};
|
48
|
+
class ExpandableSectionForSyntaxHighlighter extends Component {
|
49
|
+
constructor(props) {
|
50
|
+
var _a;
|
51
|
+
super(props);
|
52
|
+
this.expandableContentRef = createRef();
|
53
|
+
/* eslint-disable-next-line */
|
54
|
+
this.observer = () => { };
|
55
|
+
this.checkToggleVisibility = () => {
|
56
|
+
var _a;
|
57
|
+
if ((_a = this.expandableContentRef) === null || _a === void 0 ? void 0 : _a.current) {
|
58
|
+
const maxLines = this.props.truncateMaxLines || parseInt(lineClamp.value);
|
59
|
+
const totalLines = this.expandableContentRef.current.scrollHeight /
|
60
|
+
parseInt(getComputedStyle(this.expandableContentRef.current).lineHeight);
|
61
|
+
this.setState({
|
62
|
+
hasToggle: totalLines > maxLines
|
63
|
+
});
|
64
|
+
}
|
65
|
+
};
|
66
|
+
this.resize = () => {
|
67
|
+
if (this.expandableContentRef.current) {
|
68
|
+
const { offsetWidth } = this.expandableContentRef.current;
|
69
|
+
if (this.state.previousWidth !== offsetWidth) {
|
70
|
+
this.setState({ previousWidth: offsetWidth });
|
71
|
+
this.checkToggleVisibility();
|
72
|
+
}
|
73
|
+
}
|
74
|
+
};
|
75
|
+
this.handleResize = debounce(this.resize, 250);
|
76
|
+
this.state = {
|
77
|
+
isExpanded: (_a = props.isExpanded) !== null && _a !== void 0 ? _a : false,
|
78
|
+
hasToggle: true,
|
79
|
+
previousWidth: undefined
|
80
|
+
};
|
81
|
+
}
|
82
|
+
componentDidMount() {
|
83
|
+
if (this.props.variant === ExpandableSectionVariant.truncate) {
|
84
|
+
const expandableContent = this.expandableContentRef.current;
|
85
|
+
if (expandableContent) {
|
86
|
+
this.setState({ previousWidth: expandableContent.offsetWidth });
|
87
|
+
this.observer = getResizeObserver(expandableContent, this.handleResize, false);
|
88
|
+
if (this.props.truncateMaxLines) {
|
89
|
+
setLineClamp(expandableContent, this.props.truncateMaxLines, this.props.language, this.state.isExpanded);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
this.checkToggleVisibility();
|
93
|
+
}
|
94
|
+
}
|
95
|
+
componentDidUpdate(prevProps) {
|
96
|
+
if (this.props.variant === ExpandableSectionVariant.truncate &&
|
97
|
+
(prevProps.truncateMaxLines !== this.props.truncateMaxLines ||
|
98
|
+
prevProps.children !== this.props.children ||
|
99
|
+
prevProps.isExpanded !== this.props.isExpanded)) {
|
100
|
+
const expandableContent = this.expandableContentRef.current;
|
101
|
+
setLineClamp(expandableContent, this.props.truncateMaxLines, this.props.language, this.props.isExpanded);
|
102
|
+
this.checkToggleVisibility();
|
103
|
+
}
|
104
|
+
}
|
105
|
+
componentWillUnmount() {
|
106
|
+
if (this.props.variant === ExpandableSectionVariant.truncate) {
|
107
|
+
this.observer();
|
108
|
+
}
|
109
|
+
}
|
110
|
+
render() {
|
111
|
+
const _a = this.props, { className, children, isExpanded, isDetached, displaySize, isWidthLimited, isIndented, contentId, toggleId, variant } = _a, props = __rest(_a, ["className", "children", "isExpanded", "isDetached", "displaySize", "isWidthLimited", "isIndented", "contentId", "toggleId", "variant"]);
|
112
|
+
if (isDetached && !toggleId) {
|
113
|
+
/* eslint-disable no-console */
|
114
|
+
console.warn('ExpandableSection: The toggleId value must be passed in and must match the toggleId of the ExpandableSectionToggle.');
|
115
|
+
}
|
116
|
+
const uniqueContentId = contentId || getUniqueId('expandable-section-content');
|
117
|
+
const uniqueToggleId = toggleId || getUniqueId('expandable-section-toggle');
|
118
|
+
return (_jsx("div", Object.assign({ className: css(styles.expandableSection, isExpanded && styles.modifiers.expanded, displaySize === 'lg' && styles.modifiers.displayLg, isWidthLimited && styles.modifiers.limitWidth, isIndented && styles.modifiers.indented, variant === ExpandableSectionVariant.truncate && styles.modifiers.truncate, className) }, props, { children: _jsx("div", { ref: this.expandableContentRef, className: css(styles.expandableSectionContent), hidden: variant !== ExpandableSectionVariant.truncate && !isExpanded, id: uniqueContentId, "aria-labelledby": uniqueToggleId, role: "region", children: children }) })));
|
119
|
+
}
|
120
|
+
}
|
121
|
+
ExpandableSectionForSyntaxHighlighter.displayName = 'ExpandableSection';
|
122
|
+
ExpandableSectionForSyntaxHighlighter.defaultProps = {
|
123
|
+
className: '',
|
124
|
+
isDetached: false,
|
125
|
+
displaySize: 'default',
|
126
|
+
isWidthLimited: false,
|
127
|
+
isIndented: false,
|
128
|
+
variant: 'default'
|
129
|
+
};
|
130
|
+
export { ExpandableSectionForSyntaxHighlighter };
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { ReactNode } from 'react';
|
2
2
|
import type { FunctionComponent, HTMLProps, MouseEvent as ReactMouseEvent, Ref } from 'react';
|
3
|
-
import { AlertProps, AvatarProps, ButtonProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
|
3
|
+
import { AlertProps, AvatarProps, ButtonProps, ExpandableSectionProps, ExpandableSectionToggleProps, FormProps, LabelGroupProps } from '@patternfly/react-core';
|
4
4
|
import { ActionProps } from '../ResponseActions/ResponseActions';
|
5
5
|
import { SourcesCardProps } from '../SourcesCard';
|
6
6
|
import { QuickStart, QuickstartAction } from './QuickStarts/types';
|
@@ -64,9 +64,24 @@ export interface MessageProps extends Omit<HTMLProps<HTMLDivElement>, 'role'> {
|
|
64
64
|
botWord?: string;
|
65
65
|
/** Label for the English "Loading message," displayed to screenreaders when loading a message */
|
66
66
|
loadingWord?: string;
|
67
|
+
/** Props for code blocks */
|
67
68
|
codeBlockProps?: {
|
69
|
+
/** Aria label applied to code blocks */
|
68
70
|
'aria-label'?: string;
|
71
|
+
/** Class name applied to code blocks */
|
69
72
|
className?: string;
|
73
|
+
/** Whether code blocks are expandable */
|
74
|
+
isExpandable?: boolean;
|
75
|
+
/** Length of text initially shown in expandable code blocks; defaults to 10 characters */
|
76
|
+
maxLength?: number;
|
77
|
+
/** Additional props passed to expandable section if isExpandable is applied */
|
78
|
+
expandableSectionProps?: Omit<ExpandableSectionProps, 'ref'>;
|
79
|
+
/** Additional props passed to expandable toggle if isExpandable is applied */
|
80
|
+
expandableSectionToggleProps?: ExpandableSectionToggleProps;
|
81
|
+
/** Link text applied to expandable toggle when expanded */
|
82
|
+
expandedText?: string;
|
83
|
+
/** Link text applied to expandable toggle when collapsed */
|
84
|
+
collapsedText?: string;
|
70
85
|
};
|
71
86
|
/** Props for quick responses */
|
72
87
|
quickResponses?: QuickResponse[];
|
@@ -403,6 +403,30 @@ describe('Message', () => {
|
|
403
403
|
expect(screen.getByText(/url:/i)).toBeTruthy();
|
404
404
|
expect(screen.getByText(/https:\/\/raw.githubusercontent.com\/Azure-Samples\/helm-charts\/master\/docs/i)).toBeTruthy();
|
405
405
|
});
|
406
|
+
it('should render expandable code correctly', () => {
|
407
|
+
render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { isExpandable: true } }));
|
408
|
+
expect(screen.getByText('Here is some YAML code:')).toBeTruthy();
|
409
|
+
expect(screen.getByRole('button', { name: 'Copy code' })).toBeTruthy();
|
410
|
+
expect(screen.getByText(/yaml/)).toBeTruthy();
|
411
|
+
expect(screen.getByText(/apiVersion/i)).toBeTruthy();
|
412
|
+
expect(screen.getByRole('button', { name: /Show more/i })).toBeTruthy();
|
413
|
+
});
|
414
|
+
it('should handle click on expandable code correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
415
|
+
render(_jsx(Message, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { isExpandable: true } }));
|
416
|
+
const button = screen.getByRole('button', { name: /Show more/i });
|
417
|
+
yield userEvent.click(button);
|
418
|
+
expect(screen.getByRole('button', { name: /Show less/i })).toBeTruthy();
|
419
|
+
expect(screen.getByText(/yaml/)).toBeTruthy();
|
420
|
+
expect(screen.getByText(/apiVersion:/i)).toBeTruthy();
|
421
|
+
expect(screen.getByText(/helm.openshift.io\/v1beta1/i)).toBeTruthy();
|
422
|
+
expect(screen.getByText(/metadata:/i)).toBeTruthy();
|
423
|
+
expect(screen.getByText(/name:/i)).toBeTruthy();
|
424
|
+
expect(screen.getByText(/azure-sample-repo0oooo00ooo/i)).toBeTruthy();
|
425
|
+
expect(screen.getByText(/spec/i)).toBeTruthy();
|
426
|
+
expect(screen.getByText(/connectionConfig:/i)).toBeTruthy();
|
427
|
+
expect(screen.getByText(/url:/i)).toBeTruthy();
|
428
|
+
expect(screen.getByText(/https:\/\/raw.githubusercontent.com\/Azure-Samples\/helm-charts\/master\/docs/i)).toBeTruthy();
|
429
|
+
}));
|
406
430
|
it('can click copy code button', () => __awaiter(void 0, void 0, void 0, function* () {
|
407
431
|
// need explicit setup since RTL stubs clipboard if you do this
|
408
432
|
const user = userEvent.setup();
|
@@ -1 +1 @@
|
|
1
|
-
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
|
1
|
+
{"root":["../src/index.ts","../src/AttachMenu/AttachMenu.tsx","../src/AttachMenu/index.ts","../src/AttachmentEdit/AttachmentEdit.test.tsx","../src/AttachmentEdit/AttachmentEdit.tsx","../src/AttachmentEdit/index.ts","../src/Chatbot/Chatbot.test.tsx","../src/Chatbot/Chatbot.tsx","../src/Chatbot/index.ts","../src/ChatbotAlert/ChatbotAlert.test.tsx","../src/ChatbotAlert/ChatbotAlert.tsx","../src/ChatbotAlert/index.ts","../src/ChatbotContent/ChatbotContent.test.tsx","../src/ChatbotContent/ChatbotContent.tsx","../src/ChatbotContent/index.ts","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryDropdown.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.test.tsx","../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.tsx","../src/ChatbotConversationHistoryNav/EmptyState.tsx","../src/ChatbotConversationHistoryNav/LoadingState.tsx","../src/ChatbotConversationHistoryNav/index.ts","../src/ChatbotFooter/ChatbotFooter.test.tsx","../src/ChatbotFooter/ChatbotFooter.tsx","../src/ChatbotFooter/ChatbotFooternote.test.tsx","../src/ChatbotFooter/ChatbotFootnote.tsx","../src/ChatbotFooter/index.ts","../src/ChatbotHeader/ChatbotHeader.test.tsx","../src/ChatbotHeader/ChatbotHeader.tsx","../src/ChatbotHeader/ChatbotHeaderActions.test.tsx","../src/ChatbotHeader/ChatbotHeaderActions.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.test.tsx","../src/ChatbotHeader/ChatbotHeaderCloseButton.tsx","../src/ChatbotHeader/ChatbotHeaderMain.test.tsx","../src/ChatbotHeader/ChatbotHeaderMain.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.test.tsx","../src/ChatbotHeader/ChatbotHeaderMenu.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderOptionsDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.test.tsx","../src/ChatbotHeader/ChatbotHeaderSelectorDropdown.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.test.tsx","../src/ChatbotHeader/ChatbotHeaderTitle.tsx","../src/ChatbotHeader/index.ts","../src/ChatbotModal/ChatbotModal.test.tsx","../src/ChatbotModal/ChatbotModal.tsx","../src/ChatbotModal/index.ts","../src/ChatbotPopover/ChatbotPopover.tsx","../src/ChatbotPopover/index.ts","../src/ChatbotToggle/ChatbotToggle.test.tsx","../src/ChatbotToggle/ChatbotToggle.tsx","../src/ChatbotToggle/index.ts","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.test.tsx","../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.tsx","../src/ChatbotWelcomePrompt/index.ts","../src/CodeModal/CodeModal.test.tsx","../src/CodeModal/CodeModal.tsx","../src/CodeModal/index.ts","../src/Compare/Compare.test.tsx","../src/Compare/Compare.tsx","../src/Compare/index.ts","../src/FileDetails/FileDetails.test.tsx","../src/FileDetails/FileDetails.tsx","../src/FileDetails/index.ts","../src/FileDetailsLabel/FileDetailsLabel.test.tsx","../src/FileDetailsLabel/FileDetailsLabel.tsx","../src/FileDetailsLabel/index.ts","../src/FileDropZone/FileDropZone.test.tsx","../src/FileDropZone/FileDropZone.tsx","../src/FileDropZone/index.ts","../src/LoadingMessage/LoadingMessage.test.tsx","../src/LoadingMessage/LoadingMessage.tsx","../src/LoadingMessage/index.ts","../src/Message/Message.test.tsx","../src/Message/Message.tsx","../src/Message/MessageInput.tsx","../src/Message/MessageLoading.tsx","../src/Message/index.ts","../src/Message/CodeBlockMessage/CodeBlockMessage.tsx","../src/Message/CodeBlockMessage/ExpandableSectionForSyntaxHighlighter.tsx","../src/Message/ErrorMessage/ErrorMessage.tsx","../src/Message/ImageMessage/ImageMessage.tsx","../src/Message/LinkMessage/LinkMessage.tsx","../src/Message/ListMessage/ListItemMessage.tsx","../src/Message/ListMessage/OrderedListMessage.tsx","../src/Message/ListMessage/UnorderedListMessage.tsx","../src/Message/Plugins/rehypeMoveImagesOutOfParagraphs.ts","../src/Message/QuickResponse/QuickResponse.tsx","../src/Message/QuickStarts/FallbackImg.tsx","../src/Message/QuickStarts/QuickStartTile.tsx","../src/Message/QuickStarts/QuickStartTileDescription.test.tsx","../src/Message/QuickStarts/QuickStartTileDescription.tsx","../src/Message/QuickStarts/QuickStartTileHeader.tsx","../src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts","../src/Message/QuickStarts/monitor-sampleapp-quickstart.ts","../src/Message/QuickStarts/types.ts","../src/Message/TableMessage/TableMessage.tsx","../src/Message/TableMessage/TbodyMessage.tsx","../src/Message/TableMessage/TdMessage.tsx","../src/Message/TableMessage/ThMessage.tsx","../src/Message/TableMessage/TheadMessage.tsx","../src/Message/TableMessage/TrMessage.tsx","../src/Message/TextMessage/TextMessage.tsx","../src/Message/UserFeedback/CloseButton.tsx","../src/Message/UserFeedback/UserFeedback.test.tsx","../src/Message/UserFeedback/UserFeedback.tsx","../src/Message/UserFeedback/UserFeedbackComplete.test.tsx","../src/Message/UserFeedback/UserFeedbackComplete.tsx","../src/MessageBar/AttachButton.test.tsx","../src/MessageBar/AttachButton.tsx","../src/MessageBar/MessageBar.test.tsx","../src/MessageBar/MessageBar.tsx","../src/MessageBar/MicrophoneButton.tsx","../src/MessageBar/SendButton.test.tsx","../src/MessageBar/SendButton.tsx","../src/MessageBar/StopButton.test.tsx","../src/MessageBar/StopButton.tsx","../src/MessageBar/index.ts","../src/MessageBox/JumpButton.test.tsx","../src/MessageBox/JumpButton.tsx","../src/MessageBox/MessageBox.test.tsx","../src/MessageBox/MessageBox.tsx","../src/MessageBox/index.ts","../src/PreviewAttachment/PreviewAttachment.test.tsx","../src/PreviewAttachment/PreviewAttachment.tsx","../src/PreviewAttachment/index.ts","../src/ResponseActions/ResponseActionButton.test.tsx","../src/ResponseActions/ResponseActionButton.tsx","../src/ResponseActions/ResponseActions.test.tsx","../src/ResponseActions/ResponseActions.tsx","../src/ResponseActions/index.ts","../src/Settings/SettingsForm.test.tsx","../src/Settings/SettingsForm.tsx","../src/Settings/index.ts","../src/SourceDetailsMenuItem/SourceDetailsMenuItem.tsx","../src/SourceDetailsMenuItem/index.ts","../src/SourcesCard/SourcesCard.test.tsx","../src/SourcesCard/SourcesCard.tsx","../src/SourcesCard/index.ts","../src/TermsOfUse/TermsOfUse.test.tsx","../src/TermsOfUse/TermsOfUse.tsx","../src/TermsOfUse/index.ts","../src/__mocks__/rehype-external-links.ts","../src/__mocks__/rehype-sanitize.ts","../src/__mocks__/rehype-unwrap-images.tsx","../src/tracking/console_tracking_provider.ts","../src/tracking/index.ts","../src/tracking/posthog_tracking_provider.ts","../src/tracking/segment_tracking_provider.ts","../src/tracking/trackingProviderProxy.ts","../src/tracking/tracking_api.ts","../src/tracking/tracking_registry.ts","../src/tracking/tracking_spi.ts","../src/tracking/umami_tracking_provider.ts"],"version":"5.6.3"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@patternfly/chatbot",
|
3
|
-
"version": "6.3.0-prerelease.
|
3
|
+
"version": "6.3.0-prerelease.18",
|
4
4
|
"description": "This library provides React components based on PatternFly 6 that can be used to build chatbots.",
|
5
5
|
"main": "dist/cjs/index.js",
|
6
6
|
"module": "dist/esm/index.js",
|
@@ -261,6 +261,16 @@ Each time a user begins a new conversation, display a [welcome message, with pro
|
|
261
261
|
|
262
262
|
As much as possible, the suggested prompts should consider the user’s location in the service or application, or the situation their project is undergoing.
|
263
263
|
|
264
|
+
### Executing user requests
|
265
|
+
|
266
|
+
Instead of automatically initiating what sounds like a request from a user, the ChatBot should ask users to confirm or deny their intent. This differentiates moments where users are simply asking about feasibility, rather than actually making a request.
|
267
|
+
|
268
|
+
This can be done using the [quick response](/patternfly-ai/chatbot/messages#messages-with-quick-responses) buttons:
|
269
|
+
|
270
|
+
<div class="ws-docs-content-img">
|
271
|
+

|
272
|
+
</div>
|
273
|
+
|
264
274
|
### Using the conversation history menu
|
265
275
|
|
266
276
|
The ChatBot history menu contains a log of a users' previous chats. Clicking the menu icon opens a side drawer in the ChatBot window.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
---
|
2
|
+
# Sidenav top-level section
|
3
|
+
# should be the same for all markdown files
|
4
|
+
section: PatternFly-AI
|
5
|
+
subsection: ChatBot
|
6
|
+
# Sidenav secondary level section
|
7
|
+
# should be the same for all markdown files
|
8
|
+
id: Customizing messages
|
9
|
+
source: Customizing messages
|
10
|
+
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
|
11
|
+
# If you use typescript, the name of the interface to display props for
|
12
|
+
# These are found through the sourceProps function provided in patternfly-docs.source.js
|
13
|
+
sortValue: 60
|
14
|
+
---
|
15
|
+
|
16
|
+
## Modifying static content
|
17
|
+
|
18
|
+
The ChatBot extension `<Message>` component transforms Markdown to PatternFly React components via [react-markdown](https://github.com/remarkjs/react-markdown), which supports both [rehype](https://unifiedjs.com/explore/package/rehype/) and [remark](https://unifiedjs.com/explore/package/remark/) plugins for further output customization.
|
19
|
+
|
20
|
+
remark parses Markdown as input and serializes Markdown as output, while rehype does the same for HTML. This allows you to target and make transformations at specific checkpoints in the transformation process: either while the text tree is still in Markdown, or while the text tree is in HTML format. For more detailed information on the architecture of this library, see the [react-markdown documentation](https://github.com/remarkjs/react-markdown?tab=readme-ov-file#architecture).
|
21
|
+
|
22
|
+
You may need these plugins if, for example, you wanted to change the `href` on a link based on the link text. The `<Message>` prop `rehypePlugins` will accept any custom rehype plugins. We use already use these plugins in ChatBot to [render images a certain way](https://www.npmjs.com/package/rehype-unwrap-images) and [handle external links](https://www.npmjs.com/package/rehype-external-links).
|
23
|
+
|
24
|
+
There are many open source libraries available for other common customization needs. If you can't find one for your use case, [Unified](https://unifiedjs.com/) has a helpful [guide on creating custom plugins](https://unifiedjs.com/learn/guide/create-a-rehype-plugin/).
|
25
|
+
For a more direct example, if we wanted to change the `href` on links that included the text string `react`, we could write a very basic plugin like this:
|
26
|
+
|
27
|
+
```
|
28
|
+
import { visit } from 'unist-util-visit';
|
29
|
+
|
30
|
+
export const rehypeLinkHrefUpdater = (options) => (tree) => {
|
31
|
+
visit(tree, 'element', (node) => {
|
32
|
+
if (node.tagName === 'a' && node.properties) {
|
33
|
+
if (node.properties.href.includes('react')) {
|
34
|
+
node.properties.href = '#';
|
35
|
+
}
|
36
|
+
}
|
37
|
+
});
|
38
|
+
};
|
39
|
+
|
40
|
+
```
|
41
|
+
|
42
|
+
You could then pass `[rehypeLinkHrefUpdater]` to the `additionalRehypePlugins` prop on `<Message>` to have this applied to all relevant links read by that `<Message>` component.
|
43
|
+
|
44
|
+
## Modifying dynamic content
|
45
|
+
|
46
|
+
Props can also be used to modify dynamic content in messages.
|
47
|
+
|
48
|
+
Continuing with our link modification example, let's say you also wanted to add custom `onClick` events. In this case, you would not use `remark` or `rehype`, since they're for static tree manipulation.
|
49
|
+
|
50
|
+
Instead, you can utilize ChatBot features to customize dynamic content. We offer many `<Message>` props that allow you to implement custom behavior.
|
51
|
+
For example, you can use `linkProps` to pass `onClick` events and other PatternFly `<Button>` props down to links. A very basic example would be `linkProps={{onClick: (event) => console.log(event}}`, which would apply to every link in the `<Message>`. Or, you could use the `event.target`, adding your own custom `onClick` logic based on the `innerText`, `innerHTML`, or other attributes of the `event.target`.
|
@@ -15,11 +15,13 @@ export const BotMessageExample: FunctionComponent = () => {
|
|
15
15
|
const [variant, setVariant] = useState<string>('Code');
|
16
16
|
const [isOpen, setIsOpen] = useState(false);
|
17
17
|
const [selected, setSelected] = useState<string>('Message content type');
|
18
|
+
const [isExpandable, setIsExpanded] = useState(false);
|
18
19
|
|
19
20
|
/* eslint-disable indent */
|
20
21
|
const renderContent = () => {
|
21
22
|
switch (variant) {
|
22
23
|
case 'Code':
|
24
|
+
case 'Expandable code':
|
23
25
|
return code;
|
24
26
|
case 'Heading':
|
25
27
|
return heading;
|
@@ -166,6 +168,11 @@ _Italic text, formatted with single underscores_
|
|
166
168
|
setVariant(value);
|
167
169
|
setSelected(value as string);
|
168
170
|
setIsOpen(false);
|
171
|
+
if (value === 'Expandable code') {
|
172
|
+
setIsExpanded(true);
|
173
|
+
} else {
|
174
|
+
setIsExpanded(false);
|
175
|
+
}
|
169
176
|
};
|
170
177
|
|
171
178
|
const onToggleClick = () => {
|
@@ -237,6 +244,7 @@ _Italic text, formatted with single underscores_
|
|
237
244
|
>
|
238
245
|
<SelectList>
|
239
246
|
<SelectOption value="Code">Code</SelectOption>
|
247
|
+
<SelectOption value="Expandable code">Expandable code</SelectOption>
|
240
248
|
<SelectOption value="Inline code">Inline code</SelectOption>
|
241
249
|
<SelectOption value="Heading">Heading</SelectOption>
|
242
250
|
<SelectOption value="Block quotes">Block quotes</SelectOption>
|
@@ -259,6 +267,7 @@ _Italic text, formatted with single underscores_
|
|
259
267
|
variant === 'Table' ? { 'aria-label': 'App information and user roles for bot messages' } : undefined
|
260
268
|
}
|
261
269
|
error={variant === 'Error' ? error : undefined}
|
270
|
+
codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
|
262
271
|
/>
|
263
272
|
</>
|
264
273
|
);
|
@@ -15,11 +15,13 @@ export const UserMessageExample: FunctionComponent = () => {
|
|
15
15
|
const [isEditable, setIsEditable] = useState<boolean>(true);
|
16
16
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
17
17
|
const [selected, setSelected] = useState<string>('Message content type');
|
18
|
+
const [isExpandable, setIsExpanded] = useState(false);
|
18
19
|
|
19
20
|
/* eslint-disable indent */
|
20
21
|
const renderContent = () => {
|
21
22
|
switch (variant) {
|
22
23
|
case 'Code':
|
24
|
+
case 'Expandable code':
|
23
25
|
return code;
|
24
26
|
case 'Inline code':
|
25
27
|
return inlineCode;
|
@@ -166,6 +168,11 @@ _Italic text, formatted with single underscores_
|
|
166
168
|
setVariant(value);
|
167
169
|
setSelected(value as string);
|
168
170
|
setIsOpen(false);
|
171
|
+
if (value === 'Expandable code') {
|
172
|
+
setIsExpanded(true);
|
173
|
+
} else {
|
174
|
+
setIsExpanded(false);
|
175
|
+
}
|
169
176
|
};
|
170
177
|
|
171
178
|
const onToggleClick = () => {
|
@@ -215,6 +222,7 @@ _Italic text, formatted with single underscores_
|
|
215
222
|
>
|
216
223
|
<SelectList>
|
217
224
|
<SelectOption value="Code">Code</SelectOption>
|
225
|
+
<SelectOption value="Expandable code">Expandable code</SelectOption>
|
218
226
|
<SelectOption value="Inline code">Inline code</SelectOption>
|
219
227
|
<SelectOption value="Heading">Heading</SelectOption>
|
220
228
|
<SelectOption value="Block quotes">Block quotes</SelectOption>
|
@@ -241,6 +249,7 @@ _Italic text, formatted with single underscores_
|
|
241
249
|
error={variant === 'Error' ? error : undefined}
|
242
250
|
onEditUpdate={() => setIsEditable(false)}
|
243
251
|
onEditCancel={() => setIsEditable(false)}
|
252
|
+
codeBlockProps={{ isExpandable, expandableSectionProps: { truncateMaxLines: isExpandable ? 1 : undefined } }}
|
244
253
|
/>
|
245
254
|
</>
|
246
255
|
);
|