@patternfly/chatbot 6.4.0-prerelease.11 → 6.4.0-prerelease.12
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/UserFeedback/UserFeedback.d.ts +15 -1
- package/dist/cjs/Message/UserFeedback/UserFeedback.js +4 -4
- package/dist/cjs/Message/UserFeedback/UserFeedback.test.js +44 -0
- package/dist/esm/Message/UserFeedback/UserFeedback.d.ts +15 -1
- package/dist/esm/Message/UserFeedback/UserFeedback.js +4 -4
- package/dist/esm/Message/UserFeedback/UserFeedback.test.js +45 -1
- package/package.json +1 -1
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx +111 -85
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +1 -7
- package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +262 -56
- package/src/Message/UserFeedback/UserFeedback.test.tsx +107 -0
- package/src/Message/UserFeedback/UserFeedback.tsx +41 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'react';
|
|
2
|
-
import { CardProps, LabelGroupProps, OUIAProps } from '@patternfly/react-core';
|
|
2
|
+
import { ActionGroupProps, ButtonProps, CardBodyProps, CardHeaderProps, CardProps, FormProps, LabelGroupProps, OUIAProps, TextAreaProps } from '@patternfly/react-core';
|
|
3
3
|
import QuickResponse from '../QuickResponse/QuickResponse';
|
|
4
4
|
export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProps {
|
|
5
5
|
/** Additional classes for the pagination navigation container. */
|
|
@@ -34,6 +34,20 @@ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProp
|
|
|
34
34
|
focusOnLoad?: boolean;
|
|
35
35
|
/** Timestamp passed in by Message for more context in aria announcements */
|
|
36
36
|
timestamp?: string;
|
|
37
|
+
/** Additional props passed to submit button */
|
|
38
|
+
submitButtonProps?: ButtonProps;
|
|
39
|
+
/** Additional props passed to card header */
|
|
40
|
+
cardHeaderProps?: CardHeaderProps;
|
|
41
|
+
/** Additional props passed to card body */
|
|
42
|
+
cardBodyProps?: CardBodyProps;
|
|
43
|
+
/** Additional props passed to title heading */
|
|
44
|
+
headingLevelProps?: React.HTMLAttributes<HTMLHeadingElement>;
|
|
45
|
+
/** Additional props passed to form */
|
|
46
|
+
formProps?: FormProps;
|
|
47
|
+
/** Additional props passed to text area */
|
|
48
|
+
textAreaProps?: TextAreaProps;
|
|
49
|
+
/** Additional props passed to action group */
|
|
50
|
+
actionGroupProps?: ActionGroupProps;
|
|
37
51
|
}
|
|
38
52
|
declare const UserFeedback: FunctionComponent<UserFeedbackProps>;
|
|
39
53
|
export default UserFeedback;
|
|
@@ -21,7 +21,7 @@ const react_core_1 = require("@patternfly/react-core");
|
|
|
21
21
|
const QuickResponse_1 = __importDefault(require("../QuickResponse/QuickResponse"));
|
|
22
22
|
const CloseButton_1 = __importDefault(require("./CloseButton"));
|
|
23
23
|
const UserFeedback = (_a) => {
|
|
24
|
-
var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact"]);
|
|
24
|
+
var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact, children, cardHeaderProps, cardBodyProps, headingLevelProps, formProps, textAreaProps, actionGroupProps, submitButtonProps } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact", "children", "cardHeaderProps", "cardBodyProps", "headingLevelProps", "formProps", "textAreaProps", "actionGroupProps", "submitButtonProps"]);
|
|
25
25
|
const [selectedResponse, setSelectedResponse] = (0, react_1.useState)();
|
|
26
26
|
const [value, setValue] = (0, react_1.useState)('');
|
|
27
27
|
const divRef = (0, react_1.useRef)(null);
|
|
@@ -33,11 +33,11 @@ const UserFeedback = (_a) => {
|
|
|
33
33
|
}, []);
|
|
34
34
|
return (
|
|
35
35
|
/* card does not have ref forwarding; hence wrapper div */
|
|
36
|
-
(0, jsx_runtime_1.jsx)("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardHeader, { actions: {
|
|
36
|
+
(0, jsx_runtime_1.jsx)("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: (0, jsx_runtime_1.jsxs)(react_core_1.Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [(0, jsx_runtime_1.jsx)(react_core_1.CardHeader, Object.assign({ actions: {
|
|
37
37
|
actions: (0, jsx_runtime_1.jsx)(CloseButton_1.default, { onClose: onClose, ariaLabel: closeButtonAriaLabel })
|
|
38
|
-
}, children: (0, jsx_runtime_1.jsx)(HeadingLevel, { className: "pf-chatbot__feedback-card-title", children: title }) }), (0, jsx_runtime_1.jsx)(react_core_1.CardBody, { children: (0, jsx_runtime_1.jsxs)(react_core_1.Form, { className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}
|
|
38
|
+
} }, cardHeaderProps, { children: (0, jsx_runtime_1.jsx)(HeadingLevel, Object.assign({ className: "pf-chatbot__feedback-card-title" }, headingLevelProps, { children: title })) })), (0, jsx_runtime_1.jsx)(react_core_1.CardBody, Object.assign({}, cardBodyProps, { children: (0, jsx_runtime_1.jsxs)(react_core_1.Form, Object.assign({ className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}` }, formProps, { children: [quickResponses && ((0, jsx_runtime_1.jsx)(QuickResponse_1.default, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, onSelect: (id) => setSelectedResponse(id), isCompact: isCompact })), hasTextArea && ((0, jsx_runtime_1.jsx)(react_core_1.TextArea, Object.assign({ value: value, onChange: (_event, value) => {
|
|
39
39
|
setValue(value);
|
|
40
40
|
onTextAreaChange && onTextAreaChange(_event, value);
|
|
41
|
-
}, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" })), (0, jsx_runtime_1.jsx)(react_core_1.ActionGroup, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, { onClick: () => onSubmit(selectedResponse, value), children: submitWord }) })] }) })] })) }));
|
|
41
|
+
}, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" }, textAreaProps))), children, (0, jsx_runtime_1.jsx)(react_core_1.ActionGroup, Object.assign({}, actionGroupProps, { children: (0, jsx_runtime_1.jsx)(react_core_1.Button, Object.assign({ onClick: () => onSubmit(selectedResponse, value) }, submitButtonProps, { children: submitWord })) }))] })) }))] })) }));
|
|
42
42
|
};
|
|
43
43
|
exports.default = UserFeedback;
|
|
@@ -134,4 +134,48 @@ describe('UserFeedback', () => {
|
|
|
134
134
|
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, "data-testid": "card", isCompact: true }));
|
|
135
135
|
expect(react_1.screen.getByTestId('card')).toHaveClass('pf-m-compact');
|
|
136
136
|
});
|
|
137
|
+
it('should pass buttonProps to submit button', () => {
|
|
138
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, submitButtonProps: { variant: 'secondary', isDisabled: true } }));
|
|
139
|
+
const submitButton = react_1.screen.getByRole('button', { name: /Submit/i });
|
|
140
|
+
expect(submitButton).toHaveClass('pf-v6-c-button pf-m-secondary');
|
|
141
|
+
expect(submitButton).toBeDisabled();
|
|
142
|
+
});
|
|
143
|
+
it('should pass cardHeaderProps to card header', () => {
|
|
144
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardHeaderProps: { 'data-testid': 'card-header', className: 'custom-header' } }));
|
|
145
|
+
const cardHeader = react_1.screen.getByTestId('card-header');
|
|
146
|
+
expect(cardHeader).toHaveClass('custom-header');
|
|
147
|
+
});
|
|
148
|
+
it('should pass cardBodyProps to card body', () => {
|
|
149
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardBodyProps: { 'data-testid': 'card-body', className: 'custom-body' } }));
|
|
150
|
+
const cardBody = react_1.screen.getByTestId('card-body');
|
|
151
|
+
expect(cardBody).toHaveClass('custom-body');
|
|
152
|
+
});
|
|
153
|
+
it('should pass headingLevelProps to title heading', () => {
|
|
154
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, headingLevelProps: { className: 'custom-heading', id: 'feedback-title' } }));
|
|
155
|
+
const heading = react_1.screen.getByRole('heading', { level: 1, name: /Why did you choose this rating?/i });
|
|
156
|
+
expect(heading).toHaveClass('custom-heading');
|
|
157
|
+
expect(heading).toHaveAttribute('id', 'feedback-title');
|
|
158
|
+
});
|
|
159
|
+
it('should pass formProps to form', () => {
|
|
160
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, formProps: { 'data-testid': 'feedback-form', className: 'custom-form' } }));
|
|
161
|
+
const form = react_1.screen.getByTestId('feedback-form');
|
|
162
|
+
expect(form).toHaveClass('custom-form');
|
|
163
|
+
});
|
|
164
|
+
it('should pass textAreaProps to text area when hasTextArea is true', () => {
|
|
165
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, textAreaProps: { 'data-testid': 'custom-textarea', rows: 5 } }));
|
|
166
|
+
const textArea = react_1.screen.getByTestId('custom-textarea');
|
|
167
|
+
expect(textArea).toHaveAttribute('rows', '5');
|
|
168
|
+
expect(textArea).toHaveAttribute('data-testid', 'custom-textarea');
|
|
169
|
+
});
|
|
170
|
+
it('should pass actionGroupProps to action group', () => {
|
|
171
|
+
(0, react_1.render)((0, jsx_runtime_1.jsx)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, actionGroupProps: { 'data-testid': 'action-group', className: 'custom-actions' } }));
|
|
172
|
+
const actionGroup = react_1.screen.getByTestId('action-group');
|
|
173
|
+
expect(actionGroup).toHaveClass('custom-actions');
|
|
174
|
+
});
|
|
175
|
+
it('should render children', () => {
|
|
176
|
+
(0, react_1.render)((0, jsx_runtime_1.jsxs)(UserFeedback_1.default, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, children: [(0, jsx_runtime_1.jsx)("div", { "data-testid": "custom-content", children: "Custom feedback content" }), (0, jsx_runtime_1.jsx)("p", { children: "Additional paragraph" })] }));
|
|
177
|
+
expect(react_1.screen.getByTestId('custom-content')).toBeInTheDocument();
|
|
178
|
+
expect(react_1.screen.getByText('Custom feedback content')).toBeInTheDocument();
|
|
179
|
+
expect(react_1.screen.getByText('Additional paragraph')).toBeInTheDocument();
|
|
180
|
+
});
|
|
137
181
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'react';
|
|
2
|
-
import { CardProps, LabelGroupProps, OUIAProps } from '@patternfly/react-core';
|
|
2
|
+
import { ActionGroupProps, ButtonProps, CardBodyProps, CardHeaderProps, CardProps, FormProps, LabelGroupProps, OUIAProps, TextAreaProps } from '@patternfly/react-core';
|
|
3
3
|
import QuickResponse from '../QuickResponse/QuickResponse';
|
|
4
4
|
export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProps {
|
|
5
5
|
/** Additional classes for the pagination navigation container. */
|
|
@@ -34,6 +34,20 @@ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProp
|
|
|
34
34
|
focusOnLoad?: boolean;
|
|
35
35
|
/** Timestamp passed in by Message for more context in aria announcements */
|
|
36
36
|
timestamp?: string;
|
|
37
|
+
/** Additional props passed to submit button */
|
|
38
|
+
submitButtonProps?: ButtonProps;
|
|
39
|
+
/** Additional props passed to card header */
|
|
40
|
+
cardHeaderProps?: CardHeaderProps;
|
|
41
|
+
/** Additional props passed to card body */
|
|
42
|
+
cardBodyProps?: CardBodyProps;
|
|
43
|
+
/** Additional props passed to title heading */
|
|
44
|
+
headingLevelProps?: React.HTMLAttributes<HTMLHeadingElement>;
|
|
45
|
+
/** Additional props passed to form */
|
|
46
|
+
formProps?: FormProps;
|
|
47
|
+
/** Additional props passed to text area */
|
|
48
|
+
textAreaProps?: TextAreaProps;
|
|
49
|
+
/** Additional props passed to action group */
|
|
50
|
+
actionGroupProps?: ActionGroupProps;
|
|
37
51
|
}
|
|
38
52
|
declare const UserFeedback: FunctionComponent<UserFeedbackProps>;
|
|
39
53
|
export default UserFeedback;
|
|
@@ -16,7 +16,7 @@ import { ActionGroup, Button, Card, CardBody, CardHeader, Form, TextArea } from
|
|
|
16
16
|
import QuickResponse from '../QuickResponse/QuickResponse';
|
|
17
17
|
import CloseButton from './CloseButton';
|
|
18
18
|
const UserFeedback = (_a) => {
|
|
19
|
-
var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact"]);
|
|
19
|
+
var { className, timestamp, title = 'Why did you choose this rating?', hasTextArea, textAreaAriaLabel = `Provide optional additional feedback for message received at ${timestamp}`, textAreaPlaceholder = 'Provide optional additional feedback', onTextAreaChange, submitWord = 'Submit', quickResponses, quickResponseContainerProps = { 'aria-label': `Quick feedback for message received at ${timestamp}` }, onSubmit, onClose, closeButtonAriaLabel = `Close feedback for message received at ${timestamp}`, id, headingLevel: HeadingLevel = 'h1', focusOnLoad = true, isCompact, children, cardHeaderProps, cardBodyProps, headingLevelProps, formProps, textAreaProps, actionGroupProps, submitButtonProps } = _a, props = __rest(_a, ["className", "timestamp", "title", "hasTextArea", "textAreaAriaLabel", "textAreaPlaceholder", "onTextAreaChange", "submitWord", "quickResponses", "quickResponseContainerProps", "onSubmit", "onClose", "closeButtonAriaLabel", "id", "headingLevel", "focusOnLoad", "isCompact", "children", "cardHeaderProps", "cardBodyProps", "headingLevelProps", "formProps", "textAreaProps", "actionGroupProps", "submitButtonProps"]);
|
|
20
20
|
const [selectedResponse, setSelectedResponse] = useState();
|
|
21
21
|
const [value, setValue] = useState('');
|
|
22
22
|
const divRef = useRef(null);
|
|
@@ -28,11 +28,11 @@ const UserFeedback = (_a) => {
|
|
|
28
28
|
}, []);
|
|
29
29
|
return (
|
|
30
30
|
/* card does not have ref forwarding; hence wrapper div */
|
|
31
|
-
_jsx("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: _jsxs(Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [_jsx(CardHeader, { actions: {
|
|
31
|
+
_jsx("div", { ref: divRef, id: id, tabIndex: 0, "aria-label": title, children: _jsxs(Card, Object.assign({ isCompact: isCompact, className: `pf-chatbot__feedback-card ${className ? className : ''}` }, props, { children: [_jsx(CardHeader, Object.assign({ actions: {
|
|
32
32
|
actions: _jsx(CloseButton, { onClose: onClose, ariaLabel: closeButtonAriaLabel })
|
|
33
|
-
}, children: _jsx(HeadingLevel, { className: "pf-chatbot__feedback-card-title", children: title }) }), _jsx(CardBody, { children: _jsxs(Form, { className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}
|
|
33
|
+
} }, cardHeaderProps, { children: _jsx(HeadingLevel, Object.assign({ className: "pf-chatbot__feedback-card-title" }, headingLevelProps, { children: title })) })), _jsx(CardBody, Object.assign({}, cardBodyProps, { children: _jsxs(Form, Object.assign({ className: `pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}` }, formProps, { children: [quickResponses && (_jsx(QuickResponse, { quickResponses: quickResponses, quickResponseContainerProps: quickResponseContainerProps, onSelect: (id) => setSelectedResponse(id), isCompact: isCompact })), hasTextArea && (_jsx(TextArea, Object.assign({ value: value, onChange: (_event, value) => {
|
|
34
34
|
setValue(value);
|
|
35
35
|
onTextAreaChange && onTextAreaChange(_event, value);
|
|
36
|
-
}, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" })), _jsx(ActionGroup, { children: _jsx(Button, { onClick: () => onSubmit(selectedResponse, value), children: submitWord }) })] }) })] })) }));
|
|
36
|
+
}, placeholder: textAreaPlaceholder, "aria-label": textAreaAriaLabel, resizeOrientation: "vertical" }, textAreaProps))), children, _jsx(ActionGroup, Object.assign({}, actionGroupProps, { children: _jsx(Button, Object.assign({ onClick: () => onSubmit(selectedResponse, value) }, submitButtonProps, { children: submitWord })) }))] })) }))] })) }));
|
|
37
37
|
};
|
|
38
38
|
export default UserFeedback;
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { render, screen } from '@testing-library/react';
|
|
12
12
|
import '@testing-library/jest-dom';
|
|
13
13
|
import userEvent from '@testing-library/user-event';
|
|
@@ -129,4 +129,48 @@ describe('UserFeedback', () => {
|
|
|
129
129
|
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, "data-testid": "card", isCompact: true }));
|
|
130
130
|
expect(screen.getByTestId('card')).toHaveClass('pf-m-compact');
|
|
131
131
|
});
|
|
132
|
+
it('should pass buttonProps to submit button', () => {
|
|
133
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, submitButtonProps: { variant: 'secondary', isDisabled: true } }));
|
|
134
|
+
const submitButton = screen.getByRole('button', { name: /Submit/i });
|
|
135
|
+
expect(submitButton).toHaveClass('pf-v6-c-button pf-m-secondary');
|
|
136
|
+
expect(submitButton).toBeDisabled();
|
|
137
|
+
});
|
|
138
|
+
it('should pass cardHeaderProps to card header', () => {
|
|
139
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardHeaderProps: { 'data-testid': 'card-header', className: 'custom-header' } }));
|
|
140
|
+
const cardHeader = screen.getByTestId('card-header');
|
|
141
|
+
expect(cardHeader).toHaveClass('custom-header');
|
|
142
|
+
});
|
|
143
|
+
it('should pass cardBodyProps to card body', () => {
|
|
144
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, cardBodyProps: { 'data-testid': 'card-body', className: 'custom-body' } }));
|
|
145
|
+
const cardBody = screen.getByTestId('card-body');
|
|
146
|
+
expect(cardBody).toHaveClass('custom-body');
|
|
147
|
+
});
|
|
148
|
+
it('should pass headingLevelProps to title heading', () => {
|
|
149
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, headingLevelProps: { className: 'custom-heading', id: 'feedback-title' } }));
|
|
150
|
+
const heading = screen.getByRole('heading', { level: 1, name: /Why did you choose this rating?/i });
|
|
151
|
+
expect(heading).toHaveClass('custom-heading');
|
|
152
|
+
expect(heading).toHaveAttribute('id', 'feedback-title');
|
|
153
|
+
});
|
|
154
|
+
it('should pass formProps to form', () => {
|
|
155
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, formProps: { 'data-testid': 'feedback-form', className: 'custom-form' } }));
|
|
156
|
+
const form = screen.getByTestId('feedback-form');
|
|
157
|
+
expect(form).toHaveClass('custom-form');
|
|
158
|
+
});
|
|
159
|
+
it('should pass textAreaProps to text area when hasTextArea is true', () => {
|
|
160
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, hasTextArea: true, textAreaProps: { 'data-testid': 'custom-textarea', rows: 5 } }));
|
|
161
|
+
const textArea = screen.getByTestId('custom-textarea');
|
|
162
|
+
expect(textArea).toHaveAttribute('rows', '5');
|
|
163
|
+
expect(textArea).toHaveAttribute('data-testid', 'custom-textarea');
|
|
164
|
+
});
|
|
165
|
+
it('should pass actionGroupProps to action group', () => {
|
|
166
|
+
render(_jsx(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, actionGroupProps: { 'data-testid': 'action-group', className: 'custom-actions' } }));
|
|
167
|
+
const actionGroup = screen.getByTestId('action-group');
|
|
168
|
+
expect(actionGroup).toHaveClass('custom-actions');
|
|
169
|
+
});
|
|
170
|
+
it('should render children', () => {
|
|
171
|
+
render(_jsxs(UserFeedback, { timestamp: "12/12/12", onClose: jest.fn, onSubmit: jest.fn, quickResponses: MOCK_RESPONSES, children: [_jsx("div", { "data-testid": "custom-content", children: "Custom feedback content" }), _jsx("p", { children: "Additional paragraph" })] }));
|
|
172
|
+
expect(screen.getByTestId('custom-content')).toBeInTheDocument();
|
|
173
|
+
expect(screen.getByText('Custom feedback content')).toBeInTheDocument();
|
|
174
|
+
expect(screen.getByText('Additional paragraph')).toBeInTheDocument();
|
|
175
|
+
});
|
|
132
176
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/chatbot",
|
|
3
|
-
"version": "6.4.0-prerelease.
|
|
3
|
+
"version": "6.4.0-prerelease.12",
|
|
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",
|
package/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithFeedback.tsx
CHANGED
|
@@ -1,104 +1,130 @@
|
|
|
1
1
|
import { useState, FunctionComponent } from 'react';
|
|
2
2
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
|
3
3
|
import patternflyAvatar from './patternfly_avatar.jpg';
|
|
4
|
-
import { Checkbox, FormGroup,
|
|
4
|
+
import { Checkbox, FormGroup, Flex, FlexItem } from '@patternfly/react-core';
|
|
5
5
|
|
|
6
6
|
export const MessageWithFeedbackExample: FunctionComponent = () => {
|
|
7
7
|
const [hasCloseButton, setHasCloseButton] = useState(false);
|
|
8
8
|
const [hasTextArea, setHasTextArea] = useState(false);
|
|
9
|
+
const [hasChildren, setHasChildren] = useState(false);
|
|
10
|
+
|
|
11
|
+
const children = <>Do not share any personal or other sensitive information in your feedback.</>;
|
|
9
12
|
|
|
10
13
|
return (
|
|
11
14
|
<>
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsMd' }}>
|
|
16
|
+
<FlexItem>
|
|
17
|
+
<FormGroup role="radiogroup" isInline isStack fieldId="feedback-card" label="Variant">
|
|
18
|
+
<Checkbox
|
|
19
|
+
isChecked={hasTextArea}
|
|
20
|
+
onChange={() => {
|
|
21
|
+
setHasTextArea(!hasTextArea);
|
|
22
|
+
}}
|
|
23
|
+
name="feedback-card-with-text-area"
|
|
24
|
+
label="Has text area"
|
|
25
|
+
id="has-text-area"
|
|
26
|
+
/>
|
|
27
|
+
<Checkbox
|
|
28
|
+
isChecked={hasChildren}
|
|
29
|
+
onChange={() => {
|
|
30
|
+
setHasChildren(!hasChildren);
|
|
31
|
+
}}
|
|
32
|
+
name="feedback-card-with-children"
|
|
33
|
+
label="Has additional content"
|
|
34
|
+
id="has-children"
|
|
35
|
+
/>
|
|
36
|
+
</FormGroup>
|
|
37
|
+
</FlexItem>
|
|
38
|
+
<FlexItem>
|
|
39
|
+
<Message
|
|
40
|
+
name="Bot"
|
|
41
|
+
role="bot"
|
|
42
|
+
avatar={patternflyAvatar}
|
|
43
|
+
content="This is a message with the feedback card:"
|
|
44
|
+
userFeedbackForm={{
|
|
45
|
+
quickResponses: [
|
|
46
|
+
{ id: '1', content: 'Helpful information' },
|
|
47
|
+
{ id: '2', content: 'Easy to understand' },
|
|
48
|
+
{ id: '3', content: 'Resolved my issue' }
|
|
49
|
+
],
|
|
50
|
+
onSubmit: (quickResponse, additionalFeedback) =>
|
|
51
|
+
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
|
|
52
|
+
hasTextArea,
|
|
53
|
+
children: hasChildren ? children : undefined,
|
|
54
|
+
// eslint-disable-next-line no-console
|
|
55
|
+
onClose: () => console.log('closed feedback form'),
|
|
56
|
+
focusOnLoad: false
|
|
18
57
|
}}
|
|
19
|
-
name="basic-inline-radio"
|
|
20
|
-
label="Has text area"
|
|
21
|
-
id="has-text-area"
|
|
22
58
|
/>
|
|
23
|
-
</
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<Message
|
|
44
|
-
name="Bot"
|
|
45
|
-
role="bot"
|
|
46
|
-
avatar={patternflyAvatar}
|
|
47
|
-
content="This is a compact message with the feedback card:"
|
|
48
|
-
userFeedbackForm={{
|
|
49
|
-
quickResponses: [
|
|
50
|
-
{ id: '1', content: 'Helpful information' },
|
|
51
|
-
{ id: '2', content: 'Easy to understand' },
|
|
52
|
-
{ id: '3', content: 'Resolved my issue' }
|
|
53
|
-
],
|
|
54
|
-
onSubmit: (quickResponse, additionalFeedback) =>
|
|
55
|
-
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
|
|
56
|
-
hasTextArea,
|
|
57
|
-
// eslint-disable-next-line no-console
|
|
58
|
-
onClose: () => console.log('closed feedback form'),
|
|
59
|
-
focusOnLoad: false
|
|
60
|
-
}}
|
|
61
|
-
isCompact
|
|
62
|
-
/>
|
|
63
|
-
</Stack>
|
|
64
|
-
<Stack hasGutter>
|
|
65
|
-
<FormGroup role="radiogroup" isInline fieldId="feedback-thank-you" label="Variant">
|
|
66
|
-
<Checkbox
|
|
67
|
-
isChecked={hasCloseButton}
|
|
68
|
-
onChange={() => {
|
|
69
|
-
setHasCloseButton(!hasCloseButton);
|
|
59
|
+
</FlexItem>
|
|
60
|
+
<FlexItem>
|
|
61
|
+
<Message
|
|
62
|
+
name="Bot"
|
|
63
|
+
role="bot"
|
|
64
|
+
avatar={patternflyAvatar}
|
|
65
|
+
content="This is a compact message with the feedback card:"
|
|
66
|
+
userFeedbackForm={{
|
|
67
|
+
quickResponses: [
|
|
68
|
+
{ id: '1', content: 'Helpful information' },
|
|
69
|
+
{ id: '2', content: 'Easy to understand' },
|
|
70
|
+
{ id: '3', content: 'Resolved my issue' }
|
|
71
|
+
],
|
|
72
|
+
onSubmit: (quickResponse, additionalFeedback) =>
|
|
73
|
+
alert(`Selected ${quickResponse} and received the additional feedback: ${additionalFeedback}`),
|
|
74
|
+
hasTextArea,
|
|
75
|
+
children: hasChildren ? children : undefined,
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
onClose: () => console.log('closed feedback form'),
|
|
78
|
+
focusOnLoad: false
|
|
70
79
|
}}
|
|
71
|
-
|
|
72
|
-
label="Has close button"
|
|
73
|
-
id="has-close"
|
|
80
|
+
isCompact
|
|
74
81
|
/>
|
|
75
|
-
</
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
</FlexItem>
|
|
83
|
+
</Flex>
|
|
84
|
+
<Flex direction={{ default: 'column' }}>
|
|
85
|
+
<FlexItem>
|
|
86
|
+
<FormGroup role="radiogroup" isInline fieldId="feedback-thank-you" label="Variant">
|
|
87
|
+
<Checkbox
|
|
88
|
+
isChecked={hasCloseButton}
|
|
89
|
+
onChange={() => {
|
|
90
|
+
setHasCloseButton(!hasCloseButton);
|
|
91
|
+
}}
|
|
92
|
+
name="basic-inline-radio"
|
|
93
|
+
label="Has close button"
|
|
94
|
+
id="has-close"
|
|
95
|
+
/>
|
|
96
|
+
</FormGroup>
|
|
97
|
+
</FlexItem>
|
|
98
|
+
<FlexItem>
|
|
99
|
+
<Message
|
|
100
|
+
name="Bot"
|
|
101
|
+
role="bot"
|
|
102
|
+
avatar={patternflyAvatar}
|
|
103
|
+
content="This is a thank-you message, which is displayed once the feedback card is submitted:"
|
|
83
104
|
// eslint-disable-next-line no-console
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
userFeedbackComplete={{
|
|
106
|
+
// eslint-disable-next-line no-console
|
|
107
|
+
onClose: hasCloseButton ? () => console.log('closed completion message') : undefined,
|
|
108
|
+
focusOnLoad: false
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
</FlexItem>
|
|
112
|
+
<FlexItem>
|
|
113
|
+
<Message
|
|
114
|
+
name="Bot"
|
|
115
|
+
role="bot"
|
|
116
|
+
avatar={patternflyAvatar}
|
|
117
|
+
content="This is a compact thank-you message, which is displayed once the feedback card is submitted:"
|
|
95
118
|
// eslint-disable-next-line no-console
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
119
|
+
userFeedbackComplete={{
|
|
120
|
+
// eslint-disable-next-line no-console
|
|
121
|
+
onClose: hasCloseButton ? () => console.log('closed completion message') : undefined,
|
|
122
|
+
focusOnLoad: false
|
|
123
|
+
}}
|
|
124
|
+
isCompact
|
|
125
|
+
/>
|
|
126
|
+
</FlexItem>
|
|
127
|
+
</Flex>
|
|
102
128
|
</>
|
|
103
129
|
);
|
|
104
130
|
};
|
|
@@ -34,13 +34,7 @@ import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
|
|
34
34
|
import MessageDivider from '@patternfly/chatbot/dist/dynamic/MessageDivider';
|
|
35
35
|
import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle';
|
|
36
36
|
import SourcesCard from '@patternfly/chatbot/dist/dynamic/SourcesCard';
|
|
37
|
-
import { RobotIcon } from '@patternfly/react-icons
|
|
38
|
-
import InfoCircleIcon from '@patternfly/react-icons/dist/esm/icons/info-circle-icon';
|
|
39
|
-
import DownloadIcon from '@patternfly/react-icons/dist/esm/icons/download-icon';
|
|
40
|
-
import RedoIcon from '@patternfly/react-icons/dist/esm/icons/redo-icon';
|
|
41
|
-
import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
|
|
42
|
-
import ArrowCircleDownIcon from '@patternfly/react-icons/dist/esm/icons/arrow-circle-down-icon';
|
|
43
|
-
import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon';
|
|
37
|
+
import { ArrowCircleDownIcon, ArrowRightIcon, CheckCircleIcon, CubeIcon, CubesIcon, DownloadIcon, InfoCircleIcon, RedoIcon, RobotIcon } from '@patternfly/react-icons';
|
|
44
38
|
import patternflyAvatar from './patternfly_avatar.jpg';
|
|
45
39
|
import AttachmentEdit from '@patternfly/chatbot/dist/dynamic/AttachmentEdit';
|
|
46
40
|
import FileDetails from '@patternfly/chatbot/dist/dynamic/FileDetails';
|
package/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Fragment, FunctionComponent, useState, useEffect } from 'react';
|
|
2
2
|
import Message from '@patternfly/chatbot/dist/dynamic/Message';
|
|
3
3
|
import userAvatar from './user_avatar.svg';
|
|
4
|
+
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
|
4
5
|
import {
|
|
5
6
|
Accordion,
|
|
6
7
|
AccordionContent,
|
|
@@ -31,13 +32,15 @@ import {
|
|
|
31
32
|
Icon,
|
|
32
33
|
Progress,
|
|
33
34
|
ProgressMeasureLocation,
|
|
35
|
+
ExpandableSection,
|
|
36
|
+
ExpandableSectionToggle,
|
|
37
|
+
Label,
|
|
38
|
+
Tab,
|
|
39
|
+
Tabs,
|
|
40
|
+
TabTitleText,
|
|
34
41
|
Spinner
|
|
35
42
|
} from '@patternfly/react-core';
|
|
36
|
-
import ArrowCircleDownIcon from '@patternfly/react-icons
|
|
37
|
-
import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle-icon';
|
|
38
|
-
import ArrowRightIcon from '@patternfly/react-icons/dist/esm/icons/arrow-right-icon';
|
|
39
|
-
import patternflyAvatar from '../Messages/patternfly_avatar.jpg';
|
|
40
|
-
import React from 'react';
|
|
43
|
+
import { ArrowCircleDownIcon, ArrowRightIcon, CheckCircleIcon, CubeIcon, CubesIcon } from '@patternfly/react-icons';
|
|
41
44
|
|
|
42
45
|
const UserActionEndContent = () => {
|
|
43
46
|
// eslint-disable-next-line no-console
|
|
@@ -71,51 +74,6 @@ const BeforeMainContent = () => (
|
|
|
71
74
|
</div>
|
|
72
75
|
);
|
|
73
76
|
|
|
74
|
-
const downloadCard = (
|
|
75
|
-
<Card>
|
|
76
|
-
<CardHeader isToggleRightAligned>
|
|
77
|
-
<CardTitle>
|
|
78
|
-
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
|
|
79
|
-
<FlexItem>
|
|
80
|
-
<Icon size="lg" status="success">
|
|
81
|
-
<CheckCircleIcon />
|
|
82
|
-
</Icon>
|
|
83
|
-
</FlexItem>
|
|
84
|
-
<FlexItem>Your discovery ISO is ready</FlexItem>
|
|
85
|
-
</Flex>
|
|
86
|
-
</CardTitle>
|
|
87
|
-
</CardHeader>
|
|
88
|
-
|
|
89
|
-
<CardBody>
|
|
90
|
-
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsLg' }}>
|
|
91
|
-
<FlexItem>
|
|
92
|
-
<Content component={ContentVariants.p}>
|
|
93
|
-
To begin adding hosts to your bare metal cluster, you first need to boot them with the generated Discovery
|
|
94
|
-
ISO. This allows the installation program to see and manage your hardware.
|
|
95
|
-
</Content>
|
|
96
|
-
</FlexItem>
|
|
97
|
-
|
|
98
|
-
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsSm' }}>
|
|
99
|
-
<FlexItem>
|
|
100
|
-
<Button variant={ButtonVariant.primary} icon={<ArrowCircleDownIcon />} isBlock>
|
|
101
|
-
Download Discovery ISO
|
|
102
|
-
</Button>
|
|
103
|
-
</FlexItem>
|
|
104
|
-
|
|
105
|
-
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
|
|
106
|
-
<Content component={ContentVariants.small}>1.2 GB • Expires in 24 hours</Content>
|
|
107
|
-
</FlexItem>
|
|
108
|
-
</Flex>
|
|
109
|
-
</Flex>
|
|
110
|
-
</CardBody>
|
|
111
|
-
|
|
112
|
-
<CardFooter>
|
|
113
|
-
<Content component={ContentVariants.small}>
|
|
114
|
-
<strong>Next step:</strong> After downloading, boot your bare metal hosts from this ISO image.
|
|
115
|
-
</Content>
|
|
116
|
-
</CardFooter>
|
|
117
|
-
</Card>
|
|
118
|
-
);
|
|
119
77
|
interface Stage {
|
|
120
78
|
id: string;
|
|
121
79
|
name: string;
|
|
@@ -319,7 +277,7 @@ Setting up cluster console...`;
|
|
|
319
277
|
</Button>
|
|
320
278
|
</FlexItem>
|
|
321
279
|
</Flex>
|
|
322
|
-
<Card ouiaId="
|
|
280
|
+
<Card ouiaId="LiveProgressSummaryCard" isExpanded={isCardExpanded}>
|
|
323
281
|
<CardHeader
|
|
324
282
|
onExpand={onExpandCard}
|
|
325
283
|
isToggleRightAligned
|
|
@@ -415,6 +373,244 @@ Setting up cluster console...`;
|
|
|
415
373
|
);
|
|
416
374
|
};
|
|
417
375
|
|
|
376
|
+
const VersionSelectorCard = () => {
|
|
377
|
+
const [activeTabKey, setActiveTabKey] = useState<string | number>(0);
|
|
378
|
+
const [isCardSelected, setIsCardSelected] = useState('');
|
|
379
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
380
|
+
const id1 = '4.20';
|
|
381
|
+
const id2 = '4.19';
|
|
382
|
+
const id3 = '4.18';
|
|
383
|
+
const id4 = '4.17';
|
|
384
|
+
|
|
385
|
+
const onChange = (event: React.FormEvent<HTMLInputElement>) => {
|
|
386
|
+
setIsCardSelected(event.currentTarget.id);
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const onToggleExpandableSection = (isExpanded: boolean) => {
|
|
390
|
+
setIsExpanded(isExpanded);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const handleTabClick = (_event: any, tabIndex: string | number) => {
|
|
394
|
+
setActiveTabKey(tabIndex);
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const contentId = 'detached-expandable-section-content';
|
|
398
|
+
const toggleId = 'detached-expandable-section-toggle';
|
|
399
|
+
|
|
400
|
+
const generateTabContent = (title: string, subtitle: string) => (
|
|
401
|
+
<Flex direction={{ default: 'column' }} alignItems={{ default: 'alignItemsCenter' }} gap={{ default: 'gapMd' }}>
|
|
402
|
+
<FlexItem alignSelf={{ default: 'alignSelfCenter' }} className="pf-v6-u-mt-md pf-v6-u-text-align-center">
|
|
403
|
+
<div className="pf-v6-u-font-weight-bold">{title}</div>
|
|
404
|
+
<div>{subtitle}</div>
|
|
405
|
+
</FlexItem>
|
|
406
|
+
<FlexItem alignSelf={{ default: 'alignSelfStretch' }}>
|
|
407
|
+
<Card id="4.20-card" isSelectable isSelected={isCardSelected === id1}>
|
|
408
|
+
<CardHeader
|
|
409
|
+
selectableActions={{
|
|
410
|
+
selectableActionId: id1,
|
|
411
|
+
selectableActionAriaLabelledby: '4.20-card',
|
|
412
|
+
name: 'version',
|
|
413
|
+
variant: 'single',
|
|
414
|
+
onChange,
|
|
415
|
+
isHidden: true
|
|
416
|
+
}}
|
|
417
|
+
>
|
|
418
|
+
<CardTitle>
|
|
419
|
+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
|
|
420
|
+
<FlexItem>4.20.0-ec.3</FlexItem>
|
|
421
|
+
<FlexItem>
|
|
422
|
+
<Label isCompact color={isCardSelected === id1 ? 'blue' : undefined}>
|
|
423
|
+
Preview
|
|
424
|
+
</Label>
|
|
425
|
+
</FlexItem>
|
|
426
|
+
</Flex>
|
|
427
|
+
</CardTitle>
|
|
428
|
+
</CardHeader>
|
|
429
|
+
<CardBody>Developer preview • Not for production</CardBody>
|
|
430
|
+
</Card>
|
|
431
|
+
</FlexItem>
|
|
432
|
+
<FlexItem alignSelf={{ default: 'alignSelfStretch' }}>
|
|
433
|
+
<Card id="4.19-card" isSelectable isSelected={isCardSelected === id2}>
|
|
434
|
+
<CardHeader
|
|
435
|
+
selectableActions={{
|
|
436
|
+
selectableActionId: id2,
|
|
437
|
+
selectableActionAriaLabelledby: '4.19-card',
|
|
438
|
+
name: 'version',
|
|
439
|
+
variant: 'single',
|
|
440
|
+
onChange,
|
|
441
|
+
isHidden: true
|
|
442
|
+
}}
|
|
443
|
+
>
|
|
444
|
+
<CardTitle>
|
|
445
|
+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
|
|
446
|
+
<FlexItem>4.19.2</FlexItem>
|
|
447
|
+
<FlexItem>
|
|
448
|
+
<Label isCompact color={isCardSelected === id2 ? 'blue' : undefined}>
|
|
449
|
+
Latest
|
|
450
|
+
</Label>
|
|
451
|
+
</FlexItem>
|
|
452
|
+
</Flex>
|
|
453
|
+
</CardTitle>
|
|
454
|
+
</CardHeader>
|
|
455
|
+
<CardBody>Newest features • 18-month support • Recommended</CardBody>
|
|
456
|
+
</Card>
|
|
457
|
+
</FlexItem>
|
|
458
|
+
<FlexItem alignSelf={{ default: 'alignSelfStretch' }}>
|
|
459
|
+
<Card id="4.18-card" isSelectable isSelected={isCardSelected === id3}>
|
|
460
|
+
<CardHeader
|
|
461
|
+
selectableActions={{
|
|
462
|
+
selectableActionId: id3,
|
|
463
|
+
selectableActionAriaLabelledby: '4.18-card',
|
|
464
|
+
name: 'version',
|
|
465
|
+
variant: 'single',
|
|
466
|
+
onChange,
|
|
467
|
+
isHidden: true
|
|
468
|
+
}}
|
|
469
|
+
>
|
|
470
|
+
<CardTitle>4.18.19</CardTitle>
|
|
471
|
+
</CardHeader>
|
|
472
|
+
<CardBody>Previous stable • Full support</CardBody>
|
|
473
|
+
</Card>
|
|
474
|
+
<ExpandableSection isExpanded={isExpanded} isDetached toggleId={toggleId} contentId={contentId}>
|
|
475
|
+
<Flex
|
|
476
|
+
direction={{ default: 'column' }}
|
|
477
|
+
alignItems={{ default: 'alignItemsCenter' }}
|
|
478
|
+
gap={{ default: 'gapMd' }}
|
|
479
|
+
>
|
|
480
|
+
<FlexItem alignSelf={{ default: 'alignSelfStretch' }}>
|
|
481
|
+
<Card className="pf-v6-u-mt-md" id="4.17-card" isSelectable isSelected={isCardSelected === id4}>
|
|
482
|
+
<CardHeader
|
|
483
|
+
selectableActions={{
|
|
484
|
+
selectableActionId: id4,
|
|
485
|
+
selectableActionAriaLabelledby: '4.17-card',
|
|
486
|
+
name: 'version',
|
|
487
|
+
variant: 'single',
|
|
488
|
+
onChange,
|
|
489
|
+
isHidden: true
|
|
490
|
+
}}
|
|
491
|
+
>
|
|
492
|
+
<CardTitle>
|
|
493
|
+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
|
|
494
|
+
<FlexItem>4.17.34</FlexItem>
|
|
495
|
+
<FlexItem>
|
|
496
|
+
<Label isCompact color={isCardSelected === id4 ? 'blue' : undefined}>
|
|
497
|
+
Maintenance
|
|
498
|
+
</Label>
|
|
499
|
+
</FlexItem>
|
|
500
|
+
</Flex>
|
|
501
|
+
</CardTitle>
|
|
502
|
+
</CardHeader>
|
|
503
|
+
<CardBody>Maintenance support phase</CardBody>
|
|
504
|
+
</Card>
|
|
505
|
+
</FlexItem>
|
|
506
|
+
</Flex>
|
|
507
|
+
</ExpandableSection>
|
|
508
|
+
</FlexItem>
|
|
509
|
+
<FlexItem>
|
|
510
|
+
<ExpandableSectionToggle
|
|
511
|
+
isExpanded={isExpanded}
|
|
512
|
+
onToggle={onToggleExpandableSection}
|
|
513
|
+
toggleId={toggleId}
|
|
514
|
+
contentId={contentId}
|
|
515
|
+
direction="up"
|
|
516
|
+
>
|
|
517
|
+
{isExpanded ? 'Hide older versions' : 'Show older versions'}
|
|
518
|
+
</ExpandableSectionToggle>
|
|
519
|
+
</FlexItem>
|
|
520
|
+
</Flex>
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
return (
|
|
524
|
+
<Card ouiaId="VersionSelectorCard">
|
|
525
|
+
<CardBody
|
|
526
|
+
style={{ '--pf-v6-c-card--child--PaddingBlockEnd': 'var(--pf-t--global--spacer--md)' } as React.CSSProperties}
|
|
527
|
+
>
|
|
528
|
+
<Tabs activeKey={activeTabKey} onSelect={handleTabClick} aria-label="Architecture" role="region" isFilled>
|
|
529
|
+
<Tab
|
|
530
|
+
eventKey={0}
|
|
531
|
+
title={
|
|
532
|
+
<TabTitleText>
|
|
533
|
+
<Flex spaceItems={{ default: 'spaceItemsXs' }}>
|
|
534
|
+
<FlexItem>
|
|
535
|
+
<CubeIcon />
|
|
536
|
+
</FlexItem>
|
|
537
|
+
<FlexItem>Single arch</FlexItem>
|
|
538
|
+
</Flex>
|
|
539
|
+
</TabTitleText>
|
|
540
|
+
}
|
|
541
|
+
>
|
|
542
|
+
{generateTabContent('x86_64 Intel/AMD only', 'Standard deployments • Most common choice')}
|
|
543
|
+
</Tab>
|
|
544
|
+
<Tab
|
|
545
|
+
eventKey={1}
|
|
546
|
+
title={
|
|
547
|
+
<TabTitleText>
|
|
548
|
+
<Flex spaceItems={{ default: 'spaceItemsXs' }}>
|
|
549
|
+
<FlexItem>
|
|
550
|
+
<CubesIcon />
|
|
551
|
+
</FlexItem>
|
|
552
|
+
<FlexItem>Multi arch</FlexItem>
|
|
553
|
+
</Flex>
|
|
554
|
+
</TabTitleText>
|
|
555
|
+
}
|
|
556
|
+
>
|
|
557
|
+
{generateTabContent('Multi arch', 'Standard deployments')}
|
|
558
|
+
</Tab>
|
|
559
|
+
</Tabs>
|
|
560
|
+
</CardBody>
|
|
561
|
+
<CardFooter>
|
|
562
|
+
<Button isBlock isDisabled={isCardSelected === ''}>
|
|
563
|
+
Continue with selections
|
|
564
|
+
</Button>
|
|
565
|
+
</CardFooter>
|
|
566
|
+
</Card>
|
|
567
|
+
);
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const DownloadCard = () => (
|
|
571
|
+
<Card>
|
|
572
|
+
<CardHeader isToggleRightAligned>
|
|
573
|
+
<CardTitle>
|
|
574
|
+
<Flex spaceItems={{ default: 'spaceItemsSm' }}>
|
|
575
|
+
<FlexItem>
|
|
576
|
+
<Icon size="lg" status="success">
|
|
577
|
+
<CheckCircleIcon />
|
|
578
|
+
</Icon>
|
|
579
|
+
</FlexItem>
|
|
580
|
+
<FlexItem>Your discovery ISO is ready</FlexItem>
|
|
581
|
+
</Flex>
|
|
582
|
+
</CardTitle>
|
|
583
|
+
</CardHeader>
|
|
584
|
+
<CardBody>
|
|
585
|
+
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsLg' }}>
|
|
586
|
+
<FlexItem>
|
|
587
|
+
<Content component={ContentVariants.p}>
|
|
588
|
+
To begin adding hosts to your bare metal cluster, you first need to boot them with the generated Discovery
|
|
589
|
+
ISO. This allows the installation program to see and manage your hardware.
|
|
590
|
+
</Content>
|
|
591
|
+
</FlexItem>
|
|
592
|
+
|
|
593
|
+
<Flex direction={{ default: 'column' }} spaceItems={{ default: 'spaceItemsSm' }}>
|
|
594
|
+
<FlexItem>
|
|
595
|
+
<Button variant={ButtonVariant.primary} icon={<ArrowCircleDownIcon />} isBlock>
|
|
596
|
+
Download Discovery ISO
|
|
597
|
+
</Button>
|
|
598
|
+
</FlexItem>
|
|
599
|
+
|
|
600
|
+
<FlexItem alignSelf={{ default: 'alignSelfCenter' }}>
|
|
601
|
+
<Content component={ContentVariants.small}>1.2 GB • Expires in 24 hours</Content>
|
|
602
|
+
</FlexItem>
|
|
603
|
+
</Flex>
|
|
604
|
+
</Flex>
|
|
605
|
+
</CardBody>
|
|
606
|
+
<CardFooter>
|
|
607
|
+
<Content component={ContentVariants.small}>
|
|
608
|
+
<strong>Next step:</strong> After downloading, boot your bare metal hosts from this ISO image.
|
|
609
|
+
</Content>
|
|
610
|
+
</CardFooter>
|
|
611
|
+
</Card>
|
|
612
|
+
);
|
|
613
|
+
|
|
418
614
|
export const UserMessageWithExtraContent: FunctionComponent = () => (
|
|
419
615
|
<>
|
|
420
616
|
<Message
|
|
@@ -430,22 +626,32 @@ export const UserMessageWithExtraContent: FunctionComponent = () => (
|
|
|
430
626
|
}}
|
|
431
627
|
/>
|
|
432
628
|
<Message
|
|
433
|
-
avatar={
|
|
434
|
-
name="
|
|
435
|
-
role="
|
|
436
|
-
content="This is a
|
|
629
|
+
avatar={patternflyAvatar}
|
|
630
|
+
name="Bot"
|
|
631
|
+
role="bot"
|
|
632
|
+
content="This is a message with a live progress summmary card."
|
|
437
633
|
timestamp="1 hour ago"
|
|
438
634
|
extraContent={{
|
|
439
635
|
afterMainContent: <LiveProgressSummaryCard />
|
|
440
636
|
}}
|
|
441
637
|
/>
|
|
638
|
+
<Message
|
|
639
|
+
avatar={patternflyAvatar}
|
|
640
|
+
name="Bot"
|
|
641
|
+
role="bot"
|
|
642
|
+
content="This is a message with a version selector card."
|
|
643
|
+
timestamp="1 hour ago"
|
|
644
|
+
extraContent={{
|
|
645
|
+
afterMainContent: <VersionSelectorCard />
|
|
646
|
+
}}
|
|
647
|
+
/>
|
|
442
648
|
<Message
|
|
443
649
|
avatar={patternflyAvatar}
|
|
444
650
|
name="Bot"
|
|
445
651
|
role="bot"
|
|
446
652
|
content="All set! I've finished building the Discovery ISO. The next step is to download it and boot your hosts, which you can do using the summary card I've prepared for you:"
|
|
447
653
|
extraContent={{
|
|
448
|
-
endContent:
|
|
654
|
+
endContent: <DownloadCard />
|
|
449
655
|
}}
|
|
450
656
|
/>
|
|
451
657
|
</>
|
|
@@ -245,4 +245,111 @@ describe('UserFeedback', () => {
|
|
|
245
245
|
);
|
|
246
246
|
expect(screen.getByTestId('card')).toHaveClass('pf-m-compact');
|
|
247
247
|
});
|
|
248
|
+
it('should pass buttonProps to submit button', () => {
|
|
249
|
+
render(
|
|
250
|
+
<UserFeedback
|
|
251
|
+
timestamp="12/12/12"
|
|
252
|
+
onClose={jest.fn}
|
|
253
|
+
onSubmit={jest.fn}
|
|
254
|
+
quickResponses={MOCK_RESPONSES}
|
|
255
|
+
submitButtonProps={{ variant: 'secondary', isDisabled: true }}
|
|
256
|
+
/>
|
|
257
|
+
);
|
|
258
|
+
const submitButton = screen.getByRole('button', { name: /Submit/i });
|
|
259
|
+
expect(submitButton).toHaveClass('pf-v6-c-button pf-m-secondary');
|
|
260
|
+
expect(submitButton).toBeDisabled();
|
|
261
|
+
});
|
|
262
|
+
it('should pass cardHeaderProps to card header', () => {
|
|
263
|
+
render(
|
|
264
|
+
<UserFeedback
|
|
265
|
+
timestamp="12/12/12"
|
|
266
|
+
onClose={jest.fn}
|
|
267
|
+
onSubmit={jest.fn}
|
|
268
|
+
quickResponses={MOCK_RESPONSES}
|
|
269
|
+
cardHeaderProps={{ 'data-testid': 'card-header', className: 'custom-header' } as any}
|
|
270
|
+
/>
|
|
271
|
+
);
|
|
272
|
+
const cardHeader = screen.getByTestId('card-header');
|
|
273
|
+
expect(cardHeader).toHaveClass('custom-header');
|
|
274
|
+
});
|
|
275
|
+
it('should pass cardBodyProps to card body', () => {
|
|
276
|
+
render(
|
|
277
|
+
<UserFeedback
|
|
278
|
+
timestamp="12/12/12"
|
|
279
|
+
onClose={jest.fn}
|
|
280
|
+
onSubmit={jest.fn}
|
|
281
|
+
quickResponses={MOCK_RESPONSES}
|
|
282
|
+
cardBodyProps={{ 'data-testid': 'card-body', className: 'custom-body' } as any}
|
|
283
|
+
/>
|
|
284
|
+
);
|
|
285
|
+
const cardBody = screen.getByTestId('card-body');
|
|
286
|
+
expect(cardBody).toHaveClass('custom-body');
|
|
287
|
+
});
|
|
288
|
+
it('should pass headingLevelProps to title heading', () => {
|
|
289
|
+
render(
|
|
290
|
+
<UserFeedback
|
|
291
|
+
timestamp="12/12/12"
|
|
292
|
+
onClose={jest.fn}
|
|
293
|
+
onSubmit={jest.fn}
|
|
294
|
+
quickResponses={MOCK_RESPONSES}
|
|
295
|
+
headingLevelProps={{ className: 'custom-heading', id: 'feedback-title' }}
|
|
296
|
+
/>
|
|
297
|
+
);
|
|
298
|
+
const heading = screen.getByRole('heading', { level: 1, name: /Why did you choose this rating?/i });
|
|
299
|
+
expect(heading).toHaveClass('custom-heading');
|
|
300
|
+
expect(heading).toHaveAttribute('id', 'feedback-title');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should pass formProps to form', () => {
|
|
304
|
+
render(
|
|
305
|
+
<UserFeedback
|
|
306
|
+
timestamp="12/12/12"
|
|
307
|
+
onClose={jest.fn}
|
|
308
|
+
onSubmit={jest.fn}
|
|
309
|
+
quickResponses={MOCK_RESPONSES}
|
|
310
|
+
formProps={{ 'data-testid': 'feedback-form', className: 'custom-form' } as any}
|
|
311
|
+
/>
|
|
312
|
+
);
|
|
313
|
+
const form = screen.getByTestId('feedback-form');
|
|
314
|
+
expect(form).toHaveClass('custom-form');
|
|
315
|
+
});
|
|
316
|
+
it('should pass textAreaProps to text area when hasTextArea is true', () => {
|
|
317
|
+
render(
|
|
318
|
+
<UserFeedback
|
|
319
|
+
timestamp="12/12/12"
|
|
320
|
+
onClose={jest.fn}
|
|
321
|
+
onSubmit={jest.fn}
|
|
322
|
+
quickResponses={MOCK_RESPONSES}
|
|
323
|
+
hasTextArea
|
|
324
|
+
textAreaProps={{ 'data-testid': 'custom-textarea', rows: 5 } as any}
|
|
325
|
+
/>
|
|
326
|
+
);
|
|
327
|
+
const textArea = screen.getByTestId('custom-textarea');
|
|
328
|
+
expect(textArea).toHaveAttribute('rows', '5');
|
|
329
|
+
expect(textArea).toHaveAttribute('data-testid', 'custom-textarea');
|
|
330
|
+
});
|
|
331
|
+
it('should pass actionGroupProps to action group', () => {
|
|
332
|
+
render(
|
|
333
|
+
<UserFeedback
|
|
334
|
+
timestamp="12/12/12"
|
|
335
|
+
onClose={jest.fn}
|
|
336
|
+
onSubmit={jest.fn}
|
|
337
|
+
quickResponses={MOCK_RESPONSES}
|
|
338
|
+
actionGroupProps={{ 'data-testid': 'action-group', className: 'custom-actions' } as any}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
const actionGroup = screen.getByTestId('action-group');
|
|
342
|
+
expect(actionGroup).toHaveClass('custom-actions');
|
|
343
|
+
});
|
|
344
|
+
it('should render children', () => {
|
|
345
|
+
render(
|
|
346
|
+
<UserFeedback timestamp="12/12/12" onClose={jest.fn} onSubmit={jest.fn} quickResponses={MOCK_RESPONSES}>
|
|
347
|
+
<div data-testid="custom-content">Custom feedback content</div>
|
|
348
|
+
<p>Additional paragraph</p>
|
|
349
|
+
</UserFeedback>
|
|
350
|
+
);
|
|
351
|
+
expect(screen.getByTestId('custom-content')).toBeInTheDocument();
|
|
352
|
+
expect(screen.getByText('Custom feedback content')).toBeInTheDocument();
|
|
353
|
+
expect(screen.getByText('Additional paragraph')).toBeInTheDocument();
|
|
354
|
+
});
|
|
248
355
|
});
|
|
@@ -8,15 +8,21 @@ import { useState, useRef, useEffect } from 'react';
|
|
|
8
8
|
// Import PatternFly components
|
|
9
9
|
import {
|
|
10
10
|
ActionGroup,
|
|
11
|
+
ActionGroupProps,
|
|
11
12
|
Button,
|
|
13
|
+
ButtonProps,
|
|
12
14
|
Card,
|
|
13
15
|
CardBody,
|
|
16
|
+
CardBodyProps,
|
|
14
17
|
CardHeader,
|
|
18
|
+
CardHeaderProps,
|
|
15
19
|
CardProps,
|
|
16
20
|
Form,
|
|
21
|
+
FormProps,
|
|
17
22
|
LabelGroupProps,
|
|
18
23
|
OUIAProps,
|
|
19
|
-
TextArea
|
|
24
|
+
TextArea,
|
|
25
|
+
TextAreaProps
|
|
20
26
|
} from '@patternfly/react-core';
|
|
21
27
|
import QuickResponse from '../QuickResponse/QuickResponse';
|
|
22
28
|
import CloseButton from './CloseButton';
|
|
@@ -54,6 +60,20 @@ export interface UserFeedbackProps extends Omit<CardProps, 'onSubmit'>, OUIAProp
|
|
|
54
60
|
focusOnLoad?: boolean;
|
|
55
61
|
/** Timestamp passed in by Message for more context in aria announcements */
|
|
56
62
|
timestamp?: string;
|
|
63
|
+
/** Additional props passed to submit button */
|
|
64
|
+
submitButtonProps?: ButtonProps;
|
|
65
|
+
/** Additional props passed to card header */
|
|
66
|
+
cardHeaderProps?: CardHeaderProps;
|
|
67
|
+
/** Additional props passed to card body */
|
|
68
|
+
cardBodyProps?: CardBodyProps;
|
|
69
|
+
/** Additional props passed to title heading */
|
|
70
|
+
headingLevelProps?: React.HTMLAttributes<HTMLHeadingElement>;
|
|
71
|
+
/** Additional props passed to form */
|
|
72
|
+
formProps?: FormProps;
|
|
73
|
+
/** Additional props passed to text area */
|
|
74
|
+
textAreaProps?: TextAreaProps;
|
|
75
|
+
/** Additional props passed to action group */
|
|
76
|
+
actionGroupProps?: ActionGroupProps;
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
|
|
@@ -74,6 +94,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
|
|
|
74
94
|
headingLevel: HeadingLevel = 'h1',
|
|
75
95
|
focusOnLoad = true,
|
|
76
96
|
isCompact,
|
|
97
|
+
children,
|
|
98
|
+
cardHeaderProps,
|
|
99
|
+
cardBodyProps,
|
|
100
|
+
headingLevelProps,
|
|
101
|
+
formProps,
|
|
102
|
+
textAreaProps,
|
|
103
|
+
actionGroupProps,
|
|
104
|
+
submitButtonProps,
|
|
77
105
|
...props
|
|
78
106
|
}: UserFeedbackProps) => {
|
|
79
107
|
const [selectedResponse, setSelectedResponse] = useState<string>();
|
|
@@ -94,11 +122,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
|
|
|
94
122
|
actions={{
|
|
95
123
|
actions: <CloseButton onClose={onClose} ariaLabel={closeButtonAriaLabel} />
|
|
96
124
|
}}
|
|
125
|
+
{...cardHeaderProps}
|
|
97
126
|
>
|
|
98
|
-
<HeadingLevel className="pf-chatbot__feedback-card-title"
|
|
127
|
+
<HeadingLevel className="pf-chatbot__feedback-card-title" {...headingLevelProps}>
|
|
128
|
+
{title}
|
|
129
|
+
</HeadingLevel>
|
|
99
130
|
</CardHeader>
|
|
100
|
-
<CardBody>
|
|
101
|
-
<Form className={`pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}`}>
|
|
131
|
+
<CardBody {...cardBodyProps}>
|
|
132
|
+
<Form className={`pf-chatbot__feedback-card-form ${isCompact ? 'pf-m-compact' : ''}`} {...formProps}>
|
|
102
133
|
{quickResponses && (
|
|
103
134
|
<QuickResponse
|
|
104
135
|
quickResponses={quickResponses}
|
|
@@ -117,10 +148,14 @@ const UserFeedback: FunctionComponent<UserFeedbackProps> = ({
|
|
|
117
148
|
placeholder={textAreaPlaceholder}
|
|
118
149
|
aria-label={textAreaAriaLabel}
|
|
119
150
|
resizeOrientation="vertical"
|
|
151
|
+
{...textAreaProps}
|
|
120
152
|
/>
|
|
121
153
|
)}
|
|
122
|
-
|
|
123
|
-
|
|
154
|
+
{children}
|
|
155
|
+
<ActionGroup {...actionGroupProps}>
|
|
156
|
+
<Button onClick={() => onSubmit(selectedResponse, value)} {...submitButtonProps}>
|
|
157
|
+
{submitWord}
|
|
158
|
+
</Button>
|
|
124
159
|
</ActionGroup>
|
|
125
160
|
</Form>
|
|
126
161
|
</CardBody>
|