@patternfly/chatbot 2.1.0-prerelease.17 → 2.1.0-prerelease.19
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/ChatbotToggle/ChatbotToggle.d.ts +7 -1
- package/dist/cjs/ChatbotToggle/ChatbotToggle.js +4 -4
- package/dist/cjs/ChatbotToggle/ChatbotToggle.test.d.ts +1 -0
- package/dist/cjs/ChatbotToggle/ChatbotToggle.test.js +60 -0
- package/dist/cjs/Message/Message.d.ts +5 -1
- package/dist/cjs/Message/Message.js +8 -2
- package/dist/cjs/Message/Message.test.js +100 -4
- package/dist/cjs/ResponseActions/ResponseActions.test.js +38 -0
- package/dist/css/main.css +19 -12
- package/dist/css/main.css.map +1 -1
- package/dist/esm/ChatbotToggle/ChatbotToggle.d.ts +7 -1
- package/dist/esm/ChatbotToggle/ChatbotToggle.js +4 -4
- package/dist/esm/ChatbotToggle/ChatbotToggle.test.d.ts +1 -0
- package/dist/esm/ChatbotToggle/ChatbotToggle.test.js +55 -0
- package/dist/esm/Message/Message.d.ts +5 -1
- package/dist/esm/Message/Message.js +8 -2
- package/dist/esm/Message/Message.test.js +100 -4
- package/dist/esm/ResponseActions/ResponseActions.test.js +38 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx +8 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithAttachment.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +8 -2
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/PF-social-color-square.svg +19 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/PF-social-dark-square.svg +19 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx +8 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/user_avatar.svg +18 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotToggleBasic.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/ChatbotWelcomeInteraction.tsx +3 -2
- package/patternfly-docs/content/extensions/chatbot/examples/UI/CustomClosedIcon.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/SkipToContent.tsx +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/UI/SquareChatbotToggle.tsx +14 -0
- package/patternfly-docs/content/extensions/chatbot/examples/UI/UI.md +9 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/AttachmentDemos.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.md +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/demos/Chatbot.tsx +6 -4
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachment.tsx +3 -2
- package/patternfly-docs/content/extensions/chatbot/examples/demos/ChatbotAttachmentMenu.tsx +4 -3
- package/patternfly-docs/content/extensions/chatbot/examples/demos/EmbeddedChatbot.tsx +5 -3
- package/src/ChatbotToggle/ChatbotToggle.scss +11 -5
- package/src/ChatbotToggle/ChatbotToggle.test.tsx +47 -0
- package/src/ChatbotToggle/ChatbotToggle.tsx +15 -6
- package/src/Message/Message.scss +15 -9
- package/src/Message/Message.test.tsx +141 -4
- package/src/Message/Message.tsx +28 -3
- package/src/MessageBox/MessageBox.scss +2 -2
- package/src/ResponseActions/ResponseActions.test.tsx +44 -0
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/user_avatar.jpg +0 -0
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import { ButtonProps, TooltipProps } from '@patternfly/react-core';
|
3
3
|
export interface ChatbotToggleProps extends ButtonProps {
|
4
4
|
/** Contents of the tooltip applied to the toggle button */
|
5
|
-
|
5
|
+
tooltipLabel: React.ReactNode;
|
6
6
|
/** Props spread to the PF Tooltip component */
|
7
7
|
tooltipProps?: Omit<TooltipProps, 'content'>;
|
8
8
|
/** Flag indicating visibility of the chatbot appended to the toggle */
|
@@ -15,6 +15,12 @@ export interface ChatbotToggleProps extends ButtonProps {
|
|
15
15
|
closedToggleIcon?: () => JSX.Element;
|
16
16
|
/** Ref applied to toggle */
|
17
17
|
innerRef?: React.Ref<HTMLButtonElement>;
|
18
|
+
/** Whether toggle is a circle */
|
19
|
+
isRound?: boolean;
|
20
|
+
/** Class name applied to toggle */
|
21
|
+
className?: string;
|
22
|
+
/** Test id applied to default open icon */
|
23
|
+
openIconTestId?: string;
|
18
24
|
}
|
19
25
|
declare const ChatbotToggle: React.ForwardRefExoticComponent<ChatbotToggleProps & React.RefAttributes<any>>;
|
20
26
|
export default ChatbotToggle;
|
@@ -24,12 +24,12 @@ const ChatIcon = () => (react_1.default.createElement("svg", { xmlns: "http://ww
|
|
24
24
|
react_1.default.createElement("path", { fill: "var(--pf-t--global--icon--color--inverse)", stroke: "var(--pf-t--global--icon--color--inverse)", strokeLinejoin: "round", strokeWidth: ".75", d: "M3.577 14.382c0 .198.12.38.31.46l.19.04a.492.492 0 0 0 .349-.143l3.028-3.028h8.513a.489.489 0 0 0 .492-.492V2.491A.489.489 0 0 0 15.967 2H1.691a.489.489 0 0 0-.492.491v8.728c0 .135.056.262.143.349a.498.498 0 0 0 .349.143h1.878v2.663h.008v.008ZM2.19 10.72V2.983h13.278v7.729H7.24a.512.512 0 0 0-.35.143l-2.322 2.322v-1.974a.498.498 0 0 0-.142-.348.492.492 0 0 0-.35-.143H2.19v.008Z" }),
|
25
25
|
react_1.default.createElement("path", { fill: "var(--pf-t--global--text--color--inverse)", stroke: "var(--pf-t--global--text--color--inverse)", strokeLinejoin: "round", strokeWidth: ".75", d: "M22.301 9.135h-3.963a.489.489 0 0 0-.492.491c0 .27.222.492.492.492h3.472v7.737h-1.88a.404.404 0 0 0-.348.134.492.492 0 0 0-.143.35v1.973l-2.322-2.323a.492.492 0 0 0-.349-.142H8.532v-4.265a.489.489 0 0 0-.492-.492.494.494 0 0 0-.491.492v4.756c0 .277.222.492.491.492h8.514l3.028 3.028a.492.492 0 0 0 .349.142l.19-.04a.502.502 0 0 0 .31-.459V18.83h1.878c.111-.008.262-.048.349-.135a.491.491 0 0 0 .142-.349v-8.72a.489.489 0 0 0-.491-.491h-.008Z" })));
|
26
26
|
const ChatbotToggleBase = (_a) => {
|
27
|
-
var {
|
27
|
+
var { tooltipLabel, isChatbotVisible, onToggleChatbot, tooltipProps, toggleButtonLabel, closedToggleIcon: ClosedToggleIcon, innerRef, isRound = true, className, openIconTestId } = _a, props = __rest(_a, ["tooltipLabel", "isChatbotVisible", "onToggleChatbot", "tooltipProps", "toggleButtonLabel", "closedToggleIcon", "innerRef", "isRound", "className", "openIconTestId"]);
|
28
28
|
// Configure icon
|
29
29
|
const closedIcon = ClosedToggleIcon ? react_1.default.createElement(ClosedToggleIcon, null) : react_1.default.createElement(ChatIcon, null);
|
30
|
-
const icon = isChatbotVisible ? react_1.default.createElement(angle_down_icon_1.default,
|
31
|
-
return (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content:
|
32
|
-
react_1.default.createElement(react_core_1.Button, Object.assign({ className: `pf-chatbot__button ${isChatbotVisible ? 'pf-chatbot__button--active' : ''}`, variant: "plain", "aria-label": toggleButtonLabel || `${
|
30
|
+
const icon = isChatbotVisible ? react_1.default.createElement(angle_down_icon_1.default, { "data-testid": openIconTestId }) : closedIcon;
|
31
|
+
return (react_1.default.createElement(react_core_1.Tooltip, Object.assign({ content: tooltipLabel }, tooltipProps),
|
32
|
+
react_1.default.createElement(react_core_1.Button, Object.assign({ className: `pf-chatbot__button ${isChatbotVisible ? 'pf-chatbot__button--active' : ''} ${isRound ? 'pf-chatbot__button--round' : ''} ${className ? className : ''}`, variant: "plain", "aria-label": toggleButtonLabel || `${tooltipLabel} toggle`, onClick: onToggleChatbot, "aria-expanded": isChatbotVisible, icon: react_1.default.createElement(react_core_1.Icon, { isInline: true }, icon), ref: innerRef }, props))));
|
33
33
|
};
|
34
34
|
const ChatbotToggle = react_1.default.forwardRef((props, ref) => (react_1.default.createElement(ChatbotToggleBase, Object.assign({ innerRef: ref }, props))));
|
35
35
|
exports.default = ChatbotToggle;
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,60 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
const react_1 = __importDefault(require("react"));
|
16
|
+
const react_2 = require("@testing-library/react");
|
17
|
+
require("@testing-library/jest-dom");
|
18
|
+
const user_event_1 = __importDefault(require("@testing-library/user-event"));
|
19
|
+
const ChatbotToggle_1 = __importDefault(require("./ChatbotToggle"));
|
20
|
+
describe('ChatbotToggle', () => {
|
21
|
+
it('should render tooltipLabel correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
22
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Tooltip" }));
|
23
|
+
yield user_event_1.default.click(react_2.screen.getByRole('button', { name: /Tooltip toggle/i }));
|
24
|
+
expect(react_2.screen.getByRole('tooltip', { name: /Tooltip/i })).toBeTruthy();
|
25
|
+
}));
|
26
|
+
it('should render toggleButtonLabel correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
27
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", toggleButtonLabel: "Button" }));
|
28
|
+
expect(react_2.screen.getByRole('button', { name: /Button/i })).toBeTruthy();
|
29
|
+
}));
|
30
|
+
it('should call onToggleChatbot when clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
31
|
+
const spy = jest.fn();
|
32
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", onToggleChatbot: spy }));
|
33
|
+
yield user_event_1.default.click(react_2.screen.getByRole('button'));
|
34
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
35
|
+
}));
|
36
|
+
it('should handle isChatbotVisible correctly when true', () => {
|
37
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", isChatbotVisible: true, openIconTestId: "Open" }));
|
38
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
39
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button--active');
|
40
|
+
expect(react_2.screen.getByRole('button')).toHaveAttribute('aria-expanded', 'true');
|
41
|
+
expect(react_2.screen.getByTestId('Open')).toBeTruthy();
|
42
|
+
});
|
43
|
+
it('should handle isChatbotVisible correctly when false', () => {
|
44
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", isChatbotVisible: false, openIconTestId: "Open" }));
|
45
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
46
|
+
expect(react_2.screen.getByRole('button')).not.toHaveClass('pf-chatbot__button--active');
|
47
|
+
expect(react_2.screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false');
|
48
|
+
expect(react_2.screen.queryByTestId('Open')).toBeFalsy();
|
49
|
+
});
|
50
|
+
it('should handle isRound correctly', () => {
|
51
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", isRound: true }));
|
52
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
53
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button--round');
|
54
|
+
});
|
55
|
+
it('should handle className correctly', () => {
|
56
|
+
(0, react_2.render)(react_1.default.createElement(ChatbotToggle_1.default, { tooltipLabel: "Chatbot", className: "test" }));
|
57
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
58
|
+
expect(react_2.screen.getByRole('button')).toHaveClass('test');
|
59
|
+
});
|
60
|
+
});
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { LabelGroupProps, LabelProps } from '@patternfly/react-core';
|
2
|
+
import { AvatarProps, LabelGroupProps, LabelProps } from '@patternfly/react-core';
|
3
3
|
import { ActionProps } from '../ResponseActions/ResponseActions';
|
4
4
|
import { SourcesCardProps } from '../SourcesCard';
|
5
5
|
export interface QuickResponse extends Omit<LabelProps, 'children'> {
|
@@ -60,6 +60,10 @@ export interface MessageProps extends Omit<React.HTMLProps<HTMLDivElement>, 'rol
|
|
60
60
|
quickResponses?: QuickResponse[];
|
61
61
|
/** Props for quick responses container */
|
62
62
|
quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
|
63
|
+
/** Whether avatar is round */
|
64
|
+
hasRoundAvatar?: boolean;
|
65
|
+
/** Any additional props applied to the avatar, for additional customization */
|
66
|
+
avatarProps?: Omit<AvatarProps, 'alt'>;
|
63
67
|
}
|
64
68
|
export declare const Message: React.FunctionComponent<MessageProps>;
|
65
69
|
export default Message;
|
@@ -32,12 +32,18 @@ const ListItemMessage_1 = __importDefault(require("./ListMessage/ListItemMessage
|
|
32
32
|
const UnorderedListMessage_1 = __importDefault(require("./ListMessage/UnorderedListMessage"));
|
33
33
|
const OrderedListMessage_1 = __importDefault(require("./ListMessage/OrderedListMessage"));
|
34
34
|
const Message = (_a) => {
|
35
|
-
var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments"]);
|
35
|
+
var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps"]);
|
36
|
+
let avatarClassName;
|
37
|
+
if (avatarProps && 'className' in avatarProps) {
|
38
|
+
const { className } = avatarProps, rest = __rest(avatarProps, ["className"]);
|
39
|
+
avatarClassName = className;
|
40
|
+
avatarProps = Object.assign({}, rest);
|
41
|
+
}
|
36
42
|
// Keep timestamps consistent between Timestamp component and aria-label
|
37
43
|
const date = new Date();
|
38
44
|
const dateString = timestamp !== null && timestamp !== void 0 ? timestamp : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
39
45
|
return (react_1.default.createElement("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}` }, props),
|
40
|
-
react_1.default.createElement(react_core_1.Avatar, { src: avatar, alt: "" }),
|
46
|
+
react_1.default.createElement(react_core_1.Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps)),
|
41
47
|
react_1.default.createElement("div", { className: "pf-chatbot__message-contents" },
|
42
48
|
react_1.default.createElement("div", { className: "pf-chatbot__message-meta" },
|
43
49
|
name && (react_1.default.createElement("span", { className: "pf-chatbot__message-name" },
|
@@ -74,7 +74,12 @@ describe('Message', () => {
|
|
74
74
|
expect(react_2.screen.getByText('User')).toBeTruthy();
|
75
75
|
expect(react_2.screen.getByText('Hi')).toBeTruthy();
|
76
76
|
const date = new Date();
|
77
|
-
|
77
|
+
const formattedDate = date.toLocaleDateString();
|
78
|
+
expect(react_2.screen.getByText((content, element) => {
|
79
|
+
const hasText = content.includes(formattedDate);
|
80
|
+
const isVisible = (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'script' && (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'style';
|
81
|
+
return hasText && isVisible;
|
82
|
+
})).toBeInTheDocument();
|
78
83
|
expect(react_2.screen.queryByText('Loading message')).toBeFalsy();
|
79
84
|
expect(react_2.screen.getByRole('img')).toHaveAttribute('src', './img');
|
80
85
|
});
|
@@ -84,7 +89,12 @@ describe('Message', () => {
|
|
84
89
|
expect(react_2.screen.getByText('AI')).toBeTruthy();
|
85
90
|
expect(react_2.screen.getByText('Hi')).toBeTruthy();
|
86
91
|
const date = new Date();
|
87
|
-
|
92
|
+
const formattedDate = date.toLocaleDateString();
|
93
|
+
expect(react_2.screen.getByText((content, element) => {
|
94
|
+
const hasText = content.includes(formattedDate);
|
95
|
+
const isVisible = (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'script' && (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'style';
|
96
|
+
return hasText && isVisible;
|
97
|
+
})).toBeInTheDocument();
|
88
98
|
});
|
89
99
|
it('should render avatar correctly', () => {
|
90
100
|
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./testImg", role: "bot", name: "Bot", content: "Hi" }));
|
@@ -104,7 +114,12 @@ describe('Message', () => {
|
|
104
114
|
expect(react_2.screen.getByText('Hi')).toBeTruthy();
|
105
115
|
expect(react_2.screen.getByText('2 hours ago')).toBeTruthy();
|
106
116
|
const date = new Date();
|
107
|
-
|
117
|
+
const formattedDate = date.toLocaleDateString();
|
118
|
+
expect(react_2.screen.queryByText((content, element) => {
|
119
|
+
const hasText = content.includes(formattedDate);
|
120
|
+
const isVisible = (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'script' && (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'style';
|
121
|
+
return hasText && isVisible;
|
122
|
+
})).not.toBeInTheDocument();
|
108
123
|
});
|
109
124
|
it('should render attachments', () => {
|
110
125
|
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", content: "Hi", attachments: [{ name: 'testAttachment' }] }));
|
@@ -134,7 +149,12 @@ describe('Message', () => {
|
|
134
149
|
expect(react_2.screen.getByText('AI')).toBeTruthy();
|
135
150
|
expect(react_2.screen.queryByText('Hi')).toBeFalsy();
|
136
151
|
const date = new Date();
|
137
|
-
|
152
|
+
const formattedDate = date.toLocaleDateString();
|
153
|
+
expect(react_2.screen.getByText((content, element) => {
|
154
|
+
const hasText = content.includes(formattedDate);
|
155
|
+
const isVisible = (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'script' && (element === null || element === void 0 ? void 0 : element.tagName.toLowerCase()) !== 'style';
|
156
|
+
return hasText && isVisible;
|
157
|
+
})).toBeInTheDocument();
|
138
158
|
expect(react_2.screen.getByText('Loading message')).toBeTruthy();
|
139
159
|
});
|
140
160
|
it('should be able to show sources', () => __awaiter(void 0, void 0, void 0, function* () {
|
@@ -162,6 +182,59 @@ describe('Message', () => {
|
|
162
182
|
expect(react_2.screen.getByText('Loading message')).toBeTruthy();
|
163
183
|
expect(react_2.screen.queryByText('Getting started with Red Hat OpenShift')).toBeFalsy();
|
164
184
|
});
|
185
|
+
it('should be able to show quick response', () => __awaiter(void 0, void 0, void 0, function* () {
|
186
|
+
const spy = jest.fn();
|
187
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", quickResponses: [
|
188
|
+
{
|
189
|
+
id: '1',
|
190
|
+
content: 'Yes',
|
191
|
+
onClick: spy,
|
192
|
+
className: 'test'
|
193
|
+
}
|
194
|
+
] }));
|
195
|
+
const quickResponse = react_2.screen.getByRole('button', { name: /Yes/i });
|
196
|
+
expect(quickResponse).toBeTruthy();
|
197
|
+
yield user_event_1.default.click(quickResponse);
|
198
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
199
|
+
}));
|
200
|
+
it('should be able to show more than 1 quick response', () => __awaiter(void 0, void 0, void 0, function* () {
|
201
|
+
const spy = jest.fn();
|
202
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", quickResponses: [
|
203
|
+
{
|
204
|
+
id: '1',
|
205
|
+
content: 'Yes',
|
206
|
+
onClick: spy
|
207
|
+
},
|
208
|
+
{
|
209
|
+
id: '2',
|
210
|
+
content: 'No',
|
211
|
+
onClick: spy
|
212
|
+
}
|
213
|
+
] }));
|
214
|
+
expect(react_2.screen.getByRole('button', { name: /Yes/i })).toBeTruthy();
|
215
|
+
expect(react_2.screen.getByRole('button', { name: /No/i })).toBeTruthy();
|
216
|
+
}));
|
217
|
+
it('should be able to spread quickResponseContainerProps', () => __awaiter(void 0, void 0, void 0, function* () {
|
218
|
+
const spy = jest.fn();
|
219
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", quickResponses: [
|
220
|
+
{
|
221
|
+
id: '1',
|
222
|
+
content: 'Yes',
|
223
|
+
onClick: spy
|
224
|
+
},
|
225
|
+
{
|
226
|
+
id: '2',
|
227
|
+
content: 'No',
|
228
|
+
onClick: spy
|
229
|
+
}
|
230
|
+
],
|
231
|
+
// this is a LabelGroup prop that changes the default number shown
|
232
|
+
// to be different than what we use in ChatBot
|
233
|
+
quickResponseContainerProps: { numLabels: 1 } }));
|
234
|
+
expect(react_2.screen.getByRole('button', { name: /Yes/i })).toBeTruthy();
|
235
|
+
expect(react_2.screen.queryByRole('button', { name: /No/i })).toBeFalsy();
|
236
|
+
expect(react_2.screen.getByRole('button', { name: /1 more/i }));
|
237
|
+
}));
|
165
238
|
it('should be able to show actions', () => __awaiter(void 0, void 0, void 0, function* () {
|
166
239
|
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "bot", name: "Bot", content: "Hi", actions: {
|
167
240
|
// eslint-disable-next-line no-console
|
@@ -236,4 +309,27 @@ describe('Message', () => {
|
|
236
309
|
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", name: "User", content: CODE_MESSAGE, codeBlockProps: { 'aria-label': 'test' } }));
|
237
310
|
expect(react_2.screen.getByRole('button', { name: 'test' })).toBeTruthy();
|
238
311
|
});
|
312
|
+
it('should handle hasRoundAvatar correctly when it is true', () => {
|
313
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", hasRoundAvatar: true }));
|
314
|
+
expect(react_2.screen.getByRole('img')).toBeTruthy();
|
315
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar');
|
316
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar--round');
|
317
|
+
});
|
318
|
+
it('should handle hasRoundAvatar correctly when it is false', () => {
|
319
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", hasRoundAvatar: false }));
|
320
|
+
expect(react_2.screen.getByRole('img')).toBeTruthy();
|
321
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar');
|
322
|
+
expect(react_2.screen.getByRole('img')).not.toHaveClass('pf-chatbot__message-avatar--round');
|
323
|
+
});
|
324
|
+
it('should handle avatarProps correctly by spreading it onto the Message Avatar', () => {
|
325
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", avatarProps: { className: 'test' } }));
|
326
|
+
expect(react_2.screen.getByRole('img')).toBeTruthy();
|
327
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('test');
|
328
|
+
});
|
329
|
+
it('should handle avatarProps and hasRoundAvatar correctly', () => {
|
330
|
+
(0, react_2.render)(react_1.default.createElement(Message_1.default, { avatar: "./img", role: "user", name: "User", content: "Hi", avatarProps: { className: 'test' }, hasRoundAvatar: false }));
|
331
|
+
expect(react_2.screen.getByRole('img')).toBeTruthy();
|
332
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('test');
|
333
|
+
expect(react_2.screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar');
|
334
|
+
});
|
239
335
|
});
|
@@ -17,6 +17,7 @@ const react_2 = require("@testing-library/react");
|
|
17
17
|
require("@testing-library/jest-dom");
|
18
18
|
const ResponseActions_1 = __importDefault(require("./ResponseActions"));
|
19
19
|
const user_event_1 = __importDefault(require("@testing-library/user-event"));
|
20
|
+
const react_icons_1 = require("@patternfly/react-icons");
|
20
21
|
const ALL_ACTIONS = [
|
21
22
|
{ type: 'positive', label: 'Good response' },
|
22
23
|
{ type: 'negative', label: 'Bad response' },
|
@@ -24,6 +25,28 @@ const ALL_ACTIONS = [
|
|
24
25
|
{ type: 'share', label: 'Share' },
|
25
26
|
{ type: 'listen', label: 'Listen' }
|
26
27
|
];
|
28
|
+
const CUSTOM_ACTIONS = [
|
29
|
+
{
|
30
|
+
regenerate: {
|
31
|
+
ariaLabel: 'Regenerate',
|
32
|
+
onClick: jest.fn(),
|
33
|
+
tooltipContent: 'Regenerate',
|
34
|
+
icon: react_1.default.createElement(react_icons_1.RedoIcon, null)
|
35
|
+
},
|
36
|
+
download: {
|
37
|
+
ariaLabel: 'Download',
|
38
|
+
onClick: jest.fn(),
|
39
|
+
tooltipContent: 'Download',
|
40
|
+
icon: react_1.default.createElement(react_icons_1.DownloadIcon, null)
|
41
|
+
},
|
42
|
+
info: {
|
43
|
+
ariaLabel: 'Info',
|
44
|
+
onClick: jest.fn(),
|
45
|
+
tooltipContent: 'Info',
|
46
|
+
icon: react_1.default.createElement(react_icons_1.InfoCircleIcon, null)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
];
|
27
50
|
describe('ResponseActions', () => {
|
28
51
|
it('should render buttons correctly', () => {
|
29
52
|
ALL_ACTIONS.forEach(({ type, label }) => {
|
@@ -64,4 +87,19 @@ describe('ResponseActions', () => {
|
|
64
87
|
expect(react_2.screen.getByRole('button', { name: label })).toHaveClass('test');
|
65
88
|
});
|
66
89
|
});
|
90
|
+
it('should be able to add custom actions', () => {
|
91
|
+
CUSTOM_ACTIONS.forEach((action) => {
|
92
|
+
const key = Object.keys(action)[0];
|
93
|
+
(0, react_2.render)(react_1.default.createElement(ResponseActions_1.default, { actions: {
|
94
|
+
[key]: {
|
95
|
+
tooltipContent: action[key].tooltipContent,
|
96
|
+
onClick: action[key].onClick,
|
97
|
+
// doing this just because it's easier to test without a regex for the button name
|
98
|
+
ariaLabel: action[key].ariaLabel.toLowerCase(),
|
99
|
+
icon: action[key].icon
|
100
|
+
}
|
101
|
+
} }));
|
102
|
+
expect(react_2.screen.getByRole('button', { name: key })).toBeTruthy();
|
103
|
+
});
|
104
|
+
});
|
67
105
|
});
|
package/dist/css/main.css
CHANGED
@@ -532,11 +532,8 @@ html.pf-chatbot-allow--docked {
|
|
532
532
|
inset-block-end: var(--pf-t--global--spacer--md);
|
533
533
|
inset-inline-end: var(--pf-t--global--spacer--md);
|
534
534
|
background-color: var(--pf-t--global--background--color--inverse--default);
|
535
|
-
border-radius: var(--pf-t--global--border--radius--pill);
|
536
535
|
--pf-v6-c-button__icon--Color: var(--pf-t--chatbot-toggle--color);
|
537
536
|
padding: var(--pf-t--global--spacer--md);
|
538
|
-
width: 3rem;
|
539
|
-
height: 3rem;
|
540
537
|
}
|
541
538
|
.pf-v6-c-button.pf-chatbot__button:hover, .pf-v6-c-button.pf-chatbot__button:focus {
|
542
539
|
background-color: var(--pf-t--chatbot-toggle--background--hover);
|
@@ -549,6 +546,12 @@ html.pf-chatbot-allow--docked {
|
|
549
546
|
height: var(--pf-t--global--spacer--lg);
|
550
547
|
}
|
551
548
|
|
549
|
+
.pf-chatbot__button--round {
|
550
|
+
border-radius: var(--pf-t--global--border--radius--pill);
|
551
|
+
width: 3rem;
|
552
|
+
height: 3rem;
|
553
|
+
}
|
554
|
+
|
552
555
|
.pf-chatbot--layout--welcome {
|
553
556
|
padding-block-end: var(--pf-t--global--spacer--lg);
|
554
557
|
flex-direction: column;
|
@@ -781,18 +784,22 @@ html.pf-chatbot-allow--docked {
|
|
781
784
|
gap: var(--pf-t--global--spacer--lg);
|
782
785
|
padding-bottom: var(--pf-t--global--spacer--2xl);
|
783
786
|
}
|
784
|
-
.pf-chatbot__message
|
785
|
-
--pf-v6-c-
|
786
|
-
--pf-v6-c-truncate__start--MinWidth: 0ch;
|
787
|
-
}
|
788
|
-
.pf-chatbot__message .pf-v6-c-avatar {
|
789
|
-
--pf-v6-c-avatar--Width: 3rem;
|
790
|
-
--pf-v6-c-avatar--Height: 3rem;
|
787
|
+
.pf-chatbot__message-avatar.pf-v6-c-avatar {
|
788
|
+
--pf-v6-c-avatar--BorderRadius: 0;
|
791
789
|
position: sticky;
|
792
790
|
top: var(--pf-t--global--spacer--md);
|
793
791
|
object-fit: cover;
|
794
792
|
pointer-events: none;
|
795
793
|
}
|
794
|
+
.pf-chatbot__message-avatar.pf-chatbot__message-avatar--round.pf-v6-c-avatar {
|
795
|
+
--pf-v6-c-avatar--Width: 3rem;
|
796
|
+
--pf-v6-c-avatar--Height: 3rem;
|
797
|
+
--pf-v6-c-avatar--BorderRadius: var(--pf-t--global--border--radius--pill);
|
798
|
+
}
|
799
|
+
.pf-chatbot__message .pf-v6-c-truncate {
|
800
|
+
--pf-v6-c-truncate--MinWidth: 0ch;
|
801
|
+
--pf-v6-c-truncate__start--MinWidth: 0ch;
|
802
|
+
}
|
796
803
|
.pf-chatbot__message-contents {
|
797
804
|
display: flex;
|
798
805
|
flex-direction: column;
|
@@ -1363,8 +1370,8 @@ html.pf-chatbot-allow--docked {
|
|
1363
1370
|
padding: var(--pf-t--global--spacer--lg);
|
1364
1371
|
}
|
1365
1372
|
|
1366
|
-
.pf-chatbot__messagebox--bottom {
|
1367
|
-
|
1373
|
+
.pf-chatbot__messagebox--bottom > :first-child {
|
1374
|
+
margin-top: auto !important;
|
1368
1375
|
}
|
1369
1376
|
|
1370
1377
|
.pf-chatbot__messagebox-announcement {
|
package/dist/css/main.css.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;ACvFF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;IACA;;;ACfJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAQF;EACE;;;AAQF;EACE;;AACA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AASF;AAAA;AAAA;EACE;;;AC9JN;EACE;;AAEA;EACE;EACA;;;ACHJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;;EACA;AAAA;IACE;;EAGJ;AAAA;IACE;IACA;;;AAUF;EACE;;AAGJ;EACE;;;AChDJ;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;;AAQN;EAGI;AAAA;IACE;;EAEF;AAAA;IACE;;;AASJ;EACE;;AAEF;EACE;;;AAOJ;AAAA;EAEE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAOJ;EACE;;;AAOJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;;;AC1IF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;AAAA;EAEE;;AAEF;EACE;EACA;;AAEF;EACE;;;AAOJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAGJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAOJ;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAQE;EACE;;;AAQN;EACE;;;ACvFA;EAA0B;;AAMxB;EAAM;;AACN;EAAuB;;AACvB;EACE;;AAIF;EACE;EACA;;AAEF;EACE;;;ACnBN;EACE;EACA;EACA;EACA;EACA;EACA
|
1
|
+
{"version":3,"sourceRoot":"","sources":["../../src/AttachMenu/AttachMenu.scss","../../src/Chatbot/Chatbot.scss","../../src/ChatbotAlert/ChatbotAlert.scss","../../src/ChatbotContent/ChatbotContent.scss","../../src/ChatbotConversationHistoryNav/ChatbotConversationHistoryNav.scss","../../src/ChatbotFooter/ChatbotFootnote.scss","../../src/ChatbotFooter/ChatbotFooter.scss","../../src/ChatbotHeader/ChatbotHeader.scss","../../src/ChatbotModal/ChatbotModal.scss","../../src/ChatbotPopover/ChatbotPopover.scss","../../src/ChatbotToggle/ChatbotToggle.scss","../../src/ChatbotWelcomePrompt/ChatbotWelcomePrompt.scss","../../src/CodeModal/CodeModal.scss","../../src/FileDetails/FileDetails.scss","../../src/FileDetailsLabel/FileDetailsLabel.scss","../../src/FileDropZone/FileDropZone.scss","../../src/Message/Message.scss","../../src/Message/MessageLoading.scss","../../src/Message/CodeBlockMessage/CodeBlockMessage.scss","../../src/Message/TextMessage/TextMessage.scss","../../src/Message/ListMessage/ListMessage.scss","../../src/MessageBar/AttachButton.scss","../../src/MessageBar/MicrophoneButton.scss","../../src/MessageBar/SendButton.scss","../../src/MessageBar/StopButton.scss","../../src/MessageBar/MessageBar.scss","../../src/MessageBox/JumpButton.scss","../../src/MessageBox/MessageBox.scss","../../src/ResponseActions/ResponseActions.scss","../../src/SourcesCard/SourcesCard.scss","../../src/SourceDetailsMenuItem/SourceDetailsMenuItem.scss","../../src/main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;;;AAGF;AACE;AAsBA;AASA;;AA9BA;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAGF;AACE;;AACA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;;AAGF;EACE;;AAIF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACxDJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAOJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAMF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;AAAA;AAAA;EAGE;;;ACvFF;EACE;EACA;EACA;;;ACAF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;IACA;;;ACfJ;EACE;EACA;;AAIF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;;AAMJ;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;EACA;EACA;EACA;;AAIF;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIF;EACE;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;;AAKA;EACE;EACA;EACA;EACA;EACA;;AAKJ;EACE;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;;AAQF;EACE;;;AAQF;EACE;;AACA;EACE;;;AASJ;EACE;;AACA;EACE;EACA;;AAEF;EACE;;;AASF;AAAA;AAAA;EACE;;;AC9JN;EACE;;AAEA;EACE;EACA;;;ACHJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;;;AAMF;EAGI;AAAA;IACE;;EACA;AAAA;IACE;;EAGJ;AAAA;IACE;IACA;;;AAUF;EACE;;AAGJ;EACE;;;AChDJ;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;AAEA;EACE;;AAKJ;EACE;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAIJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AACA;EACE;;;AAQN;EAGI;AAAA;IACE;;EAEF;AAAA;IACE;;;AASJ;EACE;;AAEF;EACE;;;AAOJ;AAAA;EAEE;EACA;EACA;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;AAGF;AAAA;AAAA;AAAA;EAEE;EACA;EACA;;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAOJ;EACE;;;AAOJ;AAAA;EAEE;;;AAGF;EACE;;;AAGF;EACE;;;AC1IF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAEF;AAAA;EAEE;;AAEF;EACE;EACA;;AAEF;EACE;;;AAOJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAGJ;EACE;AAAA;IAEE;IACA;IACA;IACA;IACA;IACA;IACA;;;AAOJ;EACE;;;AAMF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAQE;EACE;;;AAQN;EACE;;;ACvFA;EAA0B;;AAMxB;EAAM;;AACN;EAAuB;;AACvB;EACE;;AAIF;EACE;EACA;;AAEF;EACE;;;ACnBN;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;;AAIF;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;;AC3BF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;;AAGF;EACE;;;AAOJ;EAIM;AAAA;IACE;IACA;;;AC1CN;EACE;EACA;EACA;EACA;;AAEF;EACE;AACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;EACA;;AAEF;EACE;;AAEF;EACE;EACA;;AAEF;EACE;;AAEF;EACE;;;AASA;EACE;EACA;;;ACxEN;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;EACA;EACA;EACA;;;ACvBF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EAEA;EACA;EACA;;AACA;EACE;;AAGF;AAAA;EAEE;EACA;;;AAIJ;EACE;EACA;EACA;;AAEA;EACE;;;AAKF;EACE;;AAGF;EACE;;;AAIJ;AAAA;EAEE;EACA;;AAEA;AAAA;EACE;;;AAKF;EACE;;;AAMF;AAAA;EACE;;;AC/DJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;AACA;EACE;EACA;EACA;EACA;;;AC/BF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;;AAIA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;AAKF;EACE;EACA;;AAKF;EACE;EACA;EACA;EACA;;AAKF;EACE;EACA;EACA;;AAGA;EACE;EACA;EACA;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;AAKJ;EACE;;AAEF;EACE;;AAMJ;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAIA;EACE;;AAEA;EAHF;IAII;;;AAGF;EAPF;IAQI;;;;AAQR;EACE;EACA;EACA;;;ACnHF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AC9CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1EE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;;;AD5CN;EACE;EACA;EACA;EACA;;AAGA;EACE;EACA;;AAIF;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;;AAEA;EAEE;;AAMN;EACE;EACA;EACA;EACA;EACA;;AAEA;AAAA;EAEE;EACA;EACA;;AAEF;EACE;EACA;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA;;;AC1EE;EACE;;;AAMN;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;EACA;;;AAKF;EACE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;EAKE;;AAGF;EACE;;;AC3CN;AAAA;EAEE;EACA;EACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAGE;;;AAKF;AAAA;EAEE;EACA;EACA;;;AHnBJ;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EAEE;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;IACE;;EAEF;IAEE;;;;AI9CN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAKA;EACE;;;ACbN;EACE;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;AAKJ;EACE;EACA;;AAGA;EACE;;AAKA;EACE;;;AAMR;EACE;IACE;;EAEF;IACE;;;AC1CJ;EACE;EACA;EACA;EACA;;AAEA;EAEE;;AAEA;EACE;;;AAKN;EACE;IACE;IACA;;EAEF;IACE;IACA;;;ACvBJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EAEE;;;ACTJ;EACE;EACA;EAEA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;ACvEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;ACzCJ;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAKF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EAGI;AAAA;IACE;IACA;;;AD5BN;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YACE;EAIF;;AAEA;EACE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;;AAGF;EACE;;;AE3CJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAMA;EACE;;;ACrBR;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAIA;AAAA;EACE;;AAGJ;EACE;EACA;;AAKA;AAAA;EACE;;AAGJ;EACE;;;ACrER;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAIF;EACE;EACA;;;AAGA;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;ACJF;EAKE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EASA;EACA;EAEA;EAEA;EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;EAMA;EAKA;EAEA;EACA;EACA;EAEA;EACA;EACA;EAEA;;;AAMF;EACE;EACA;EAEA;EAEA;EACA;;;AAGF;EACE;EACA","file":"main.css"}
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import { ButtonProps, TooltipProps } from '@patternfly/react-core';
|
3
3
|
export interface ChatbotToggleProps extends ButtonProps {
|
4
4
|
/** Contents of the tooltip applied to the toggle button */
|
5
|
-
|
5
|
+
tooltipLabel: React.ReactNode;
|
6
6
|
/** Props spread to the PF Tooltip component */
|
7
7
|
tooltipProps?: Omit<TooltipProps, 'content'>;
|
8
8
|
/** Flag indicating visibility of the chatbot appended to the toggle */
|
@@ -15,6 +15,12 @@ export interface ChatbotToggleProps extends ButtonProps {
|
|
15
15
|
closedToggleIcon?: () => JSX.Element;
|
16
16
|
/** Ref applied to toggle */
|
17
17
|
innerRef?: React.Ref<HTMLButtonElement>;
|
18
|
+
/** Whether toggle is a circle */
|
19
|
+
isRound?: boolean;
|
20
|
+
/** Class name applied to toggle */
|
21
|
+
className?: string;
|
22
|
+
/** Test id applied to default open icon */
|
23
|
+
openIconTestId?: string;
|
18
24
|
}
|
19
25
|
declare const ChatbotToggle: React.ForwardRefExoticComponent<ChatbotToggleProps & React.RefAttributes<any>>;
|
20
26
|
export default ChatbotToggle;
|
@@ -19,12 +19,12 @@ const ChatIcon = () => (React.createElement("svg", { xmlns: "http://www.w3.org/2
|
|
19
19
|
React.createElement("path", { fill: "var(--pf-t--global--icon--color--inverse)", stroke: "var(--pf-t--global--icon--color--inverse)", strokeLinejoin: "round", strokeWidth: ".75", d: "M3.577 14.382c0 .198.12.38.31.46l.19.04a.492.492 0 0 0 .349-.143l3.028-3.028h8.513a.489.489 0 0 0 .492-.492V2.491A.489.489 0 0 0 15.967 2H1.691a.489.489 0 0 0-.492.491v8.728c0 .135.056.262.143.349a.498.498 0 0 0 .349.143h1.878v2.663h.008v.008ZM2.19 10.72V2.983h13.278v7.729H7.24a.512.512 0 0 0-.35.143l-2.322 2.322v-1.974a.498.498 0 0 0-.142-.348.492.492 0 0 0-.35-.143H2.19v.008Z" }),
|
20
20
|
React.createElement("path", { fill: "var(--pf-t--global--text--color--inverse)", stroke: "var(--pf-t--global--text--color--inverse)", strokeLinejoin: "round", strokeWidth: ".75", d: "M22.301 9.135h-3.963a.489.489 0 0 0-.492.491c0 .27.222.492.492.492h3.472v7.737h-1.88a.404.404 0 0 0-.348.134.492.492 0 0 0-.143.35v1.973l-2.322-2.323a.492.492 0 0 0-.349-.142H8.532v-4.265a.489.489 0 0 0-.492-.492.494.494 0 0 0-.491.492v4.756c0 .277.222.492.491.492h8.514l3.028 3.028a.492.492 0 0 0 .349.142l.19-.04a.502.502 0 0 0 .31-.459V18.83h1.878c.111-.008.262-.048.349-.135a.491.491 0 0 0 .142-.349v-8.72a.489.489 0 0 0-.491-.491h-.008Z" })));
|
21
21
|
const ChatbotToggleBase = (_a) => {
|
22
|
-
var {
|
22
|
+
var { tooltipLabel, isChatbotVisible, onToggleChatbot, tooltipProps, toggleButtonLabel, closedToggleIcon: ClosedToggleIcon, innerRef, isRound = true, className, openIconTestId } = _a, props = __rest(_a, ["tooltipLabel", "isChatbotVisible", "onToggleChatbot", "tooltipProps", "toggleButtonLabel", "closedToggleIcon", "innerRef", "isRound", "className", "openIconTestId"]);
|
23
23
|
// Configure icon
|
24
24
|
const closedIcon = ClosedToggleIcon ? React.createElement(ClosedToggleIcon, null) : React.createElement(ChatIcon, null);
|
25
|
-
const icon = isChatbotVisible ? React.createElement(AngleDownIcon,
|
26
|
-
return (React.createElement(Tooltip, Object.assign({ content:
|
27
|
-
React.createElement(Button, Object.assign({ className: `pf-chatbot__button ${isChatbotVisible ? 'pf-chatbot__button--active' : ''}`, variant: "plain", "aria-label": toggleButtonLabel || `${
|
25
|
+
const icon = isChatbotVisible ? React.createElement(AngleDownIcon, { "data-testid": openIconTestId }) : closedIcon;
|
26
|
+
return (React.createElement(Tooltip, Object.assign({ content: tooltipLabel }, tooltipProps),
|
27
|
+
React.createElement(Button, Object.assign({ className: `pf-chatbot__button ${isChatbotVisible ? 'pf-chatbot__button--active' : ''} ${isRound ? 'pf-chatbot__button--round' : ''} ${className ? className : ''}`, variant: "plain", "aria-label": toggleButtonLabel || `${tooltipLabel} toggle`, onClick: onToggleChatbot, "aria-expanded": isChatbotVisible, icon: React.createElement(Icon, { isInline: true }, icon), ref: innerRef }, props))));
|
28
28
|
};
|
29
29
|
const ChatbotToggle = React.forwardRef((props, ref) => (React.createElement(ChatbotToggleBase, Object.assign({ innerRef: ref }, props))));
|
30
30
|
export default ChatbotToggle;
|
@@ -0,0 +1 @@
|
|
1
|
+
import '@testing-library/jest-dom';
|
@@ -0,0 +1,55 @@
|
|
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
|
+
};
|
10
|
+
import React from 'react';
|
11
|
+
import { render, screen } from '@testing-library/react';
|
12
|
+
import '@testing-library/jest-dom';
|
13
|
+
import userEvent from '@testing-library/user-event';
|
14
|
+
import ChatbotToggle from './ChatbotToggle';
|
15
|
+
describe('ChatbotToggle', () => {
|
16
|
+
it('should render tooltipLabel correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
17
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Tooltip" }));
|
18
|
+
yield userEvent.click(screen.getByRole('button', { name: /Tooltip toggle/i }));
|
19
|
+
expect(screen.getByRole('tooltip', { name: /Tooltip/i })).toBeTruthy();
|
20
|
+
}));
|
21
|
+
it('should render toggleButtonLabel correctly', () => __awaiter(void 0, void 0, void 0, function* () {
|
22
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", toggleButtonLabel: "Button" }));
|
23
|
+
expect(screen.getByRole('button', { name: /Button/i })).toBeTruthy();
|
24
|
+
}));
|
25
|
+
it('should call onToggleChatbot when clicked', () => __awaiter(void 0, void 0, void 0, function* () {
|
26
|
+
const spy = jest.fn();
|
27
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", onToggleChatbot: spy }));
|
28
|
+
yield userEvent.click(screen.getByRole('button'));
|
29
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
30
|
+
}));
|
31
|
+
it('should handle isChatbotVisible correctly when true', () => {
|
32
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", isChatbotVisible: true, openIconTestId: "Open" }));
|
33
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
34
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button--active');
|
35
|
+
expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'true');
|
36
|
+
expect(screen.getByTestId('Open')).toBeTruthy();
|
37
|
+
});
|
38
|
+
it('should handle isChatbotVisible correctly when false', () => {
|
39
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", isChatbotVisible: false, openIconTestId: "Open" }));
|
40
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
41
|
+
expect(screen.getByRole('button')).not.toHaveClass('pf-chatbot__button--active');
|
42
|
+
expect(screen.getByRole('button')).toHaveAttribute('aria-expanded', 'false');
|
43
|
+
expect(screen.queryByTestId('Open')).toBeFalsy();
|
44
|
+
});
|
45
|
+
it('should handle isRound correctly', () => {
|
46
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", isRound: true }));
|
47
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
48
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button--round');
|
49
|
+
});
|
50
|
+
it('should handle className correctly', () => {
|
51
|
+
render(React.createElement(ChatbotToggle, { tooltipLabel: "Chatbot", className: "test" }));
|
52
|
+
expect(screen.getByRole('button')).toHaveClass('pf-chatbot__button');
|
53
|
+
expect(screen.getByRole('button')).toHaveClass('test');
|
54
|
+
});
|
55
|
+
});
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import { LabelGroupProps, LabelProps } from '@patternfly/react-core';
|
2
|
+
import { AvatarProps, LabelGroupProps, LabelProps } from '@patternfly/react-core';
|
3
3
|
import { ActionProps } from '../ResponseActions/ResponseActions';
|
4
4
|
import { SourcesCardProps } from '../SourcesCard';
|
5
5
|
export interface QuickResponse extends Omit<LabelProps, 'children'> {
|
@@ -60,6 +60,10 @@ export interface MessageProps extends Omit<React.HTMLProps<HTMLDivElement>, 'rol
|
|
60
60
|
quickResponses?: QuickResponse[];
|
61
61
|
/** Props for quick responses container */
|
62
62
|
quickResponseContainerProps?: Omit<LabelGroupProps, 'ref'>;
|
63
|
+
/** Whether avatar is round */
|
64
|
+
hasRoundAvatar?: boolean;
|
65
|
+
/** Any additional props applied to the avatar, for additional customization */
|
66
|
+
avatarProps?: Omit<AvatarProps, 'alt'>;
|
63
67
|
}
|
64
68
|
export declare const Message: React.FunctionComponent<MessageProps>;
|
65
69
|
export default Message;
|
@@ -26,12 +26,18 @@ import ListItemMessage from './ListMessage/ListItemMessage';
|
|
26
26
|
import UnorderedListMessage from './ListMessage/UnorderedListMessage';
|
27
27
|
import OrderedListMessage from './ListMessage/OrderedListMessage';
|
28
28
|
export const Message = (_a) => {
|
29
|
-
var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments"]);
|
29
|
+
var { role, content, name, avatar, timestamp, isLoading, actions, sources, botWord = 'AI', loadingWord = 'Loading message', codeBlockProps, quickResponses, quickResponseContainerProps = { numLabels: 5 }, attachments, hasRoundAvatar = true, avatarProps } = _a, props = __rest(_a, ["role", "content", "name", "avatar", "timestamp", "isLoading", "actions", "sources", "botWord", "loadingWord", "codeBlockProps", "quickResponses", "quickResponseContainerProps", "attachments", "hasRoundAvatar", "avatarProps"]);
|
30
|
+
let avatarClassName;
|
31
|
+
if (avatarProps && 'className' in avatarProps) {
|
32
|
+
const { className } = avatarProps, rest = __rest(avatarProps, ["className"]);
|
33
|
+
avatarClassName = className;
|
34
|
+
avatarProps = Object.assign({}, rest);
|
35
|
+
}
|
30
36
|
// Keep timestamps consistent between Timestamp component and aria-label
|
31
37
|
const date = new Date();
|
32
38
|
const dateString = timestamp !== null && timestamp !== void 0 ? timestamp : `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
|
33
39
|
return (React.createElement("section", Object.assign({ "aria-label": `Message from ${role} - ${dateString}`, className: `pf-chatbot__message pf-chatbot__message--${role}` }, props),
|
34
|
-
React.createElement(Avatar, { src: avatar, alt: "" }),
|
40
|
+
React.createElement(Avatar, Object.assign({ className: `pf-chatbot__message-avatar ${hasRoundAvatar ? 'pf-chatbot__message-avatar--round' : ''} ${avatarClassName ? avatarClassName : ''}`, src: avatar, alt: "" }, avatarProps)),
|
35
41
|
React.createElement("div", { className: "pf-chatbot__message-contents" },
|
36
42
|
React.createElement("div", { className: "pf-chatbot__message-meta" },
|
37
43
|
name && (React.createElement("span", { className: "pf-chatbot__message-name" },
|