diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx
index 8f855e213..e24d28448 100644
--- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx
+++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/BotMessage.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import Message from '@patternfly/chatbot/dist/dynamic/Message';
import patternflyAvatar from './patternfly_avatar.jpg';
import squareImg from './PF-social-color-square.svg';
-import { Form, FormGroup, Radio } from '@patternfly/react-core';
+import { AlertActionLink, Form, FormGroup, Radio } from '@patternfly/react-core';
export const BotMessageExample: React.FunctionComponent = () => {
const [variant, setVariant] = React.useState('code');
@@ -140,6 +140,21 @@ _Italic text, formatted with single underscores_
const image = ``;
+ const error = {
+ title: 'Could not load chat',
+ children: 'Wait a few minutes and check your network settings. If the issue persists: ',
+ actionLinks: (
+
+
+ Start a new chat
+
+
+ Contact support
+
+
+ )
+ };
+
return (
<>
+ setVariant('error')}
+ name="bot-message-error"
+ label="Error"
+ id="error"
+ />
>
);
diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx
index af45b8128..148f29e5f 100644
--- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx
+++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessage.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import Message from '@patternfly/chatbot/dist/dynamic/Message';
import userAvatar from './user_avatar.svg';
-import { Form, FormGroup, Radio } from '@patternfly/react-core';
+import { AlertActionLink, Form, FormGroup, Radio } from '@patternfly/react-core';
export const UserMessageExample: React.FunctionComponent = () => {
const [variant, setVariant] = React.useState('code');
@@ -140,6 +140,21 @@ _Italic text, formatted with single underscores_
const image = ``;
+ const error = {
+ title: 'Could not load chat',
+ children: 'Wait a few minutes and check your network settings. If the issue persists: ',
+ actionLinks: (
+
+
+ Start a new chat
+
+
+ Contact support
+
+
+ )
+ };
+
return (
<>
+ setVariant('error')}
+ name="user-message-error"
+ label="Error"
+ id="user-error"
+ />
>
);
diff --git a/packages/module/src/Message/ErrorMessage/ErrorMessage.tsx b/packages/module/src/Message/ErrorMessage/ErrorMessage.tsx
new file mode 100644
index 000000000..cdfa78a5f
--- /dev/null
+++ b/packages/module/src/Message/ErrorMessage/ErrorMessage.tsx
@@ -0,0 +1,14 @@
+// ============================================================================
+// Chatbot Main - Message - Content - Error
+// ============================================================================
+
+import React from 'react';
+import { Alert, AlertProps } from '@patternfly/react-core';
+
+const ErrorMessage = ({ title, actionLinks, children, ...props }: AlertProps) => (
+
+ {children}
+
+);
+
+export default ErrorMessage;
diff --git a/packages/module/src/Message/Message.test.tsx b/packages/module/src/Message/Message.test.tsx
index 567049476..d16ed1cf4 100644
--- a/packages/module/src/Message/Message.test.tsx
+++ b/packages/module/src/Message/Message.test.tsx
@@ -6,6 +6,7 @@ import userEvent from '@testing-library/user-event';
import { monitorSampleAppQuickStart } from './QuickStarts/monitor-sampleapp-quickstart';
import { monitorSampleAppQuickStartWithImage } from './QuickStarts/monitor-sampleapp-quickstart-with-image';
import rehypeExternalLinks from '../__mocks__/rehype-external-links';
+import { AlertActionLink } from '@patternfly/react-core';
const ALL_ACTIONS = [
{ label: /Good response/i },
@@ -141,6 +142,20 @@ const EMPTY_TABLE = `
const IMAGE = ``;
+const ERROR = {
+ title: 'Could not load chat',
+ children: 'Wait a few minutes and check your network settings. If the issue persists: ',
+ actionLinks: (
+
+
+ Start a new chat
+
+
+ Contact support
+
+
+ )
+};
const checkListItemsRendered = () => {
const items = ['Item 1', 'Item 2', 'Item 3'];
expect(screen.getAllByRole('listitem')).toHaveLength(3);
@@ -769,4 +784,21 @@ describe('Message', () => {
// we are mocking rehype libraries, so we can't test target _blank addition on links directly with RTL
expect(rehypeExternalLinks).not.toHaveBeenCalled();
});
+ it('should handle error correctly', () => {
+ render();
+ expect(screen.getByRole('heading', { name: /Could not load chat/i })).toBeTruthy();
+ expect(screen.getByRole('link', { name: /Start a new chat/i })).toBeTruthy();
+ expect(screen.getByRole('link', { name: /Contact support/i })).toBeTruthy();
+ expect(screen.getByText('Wait a few minutes and check your network settings. If the issue persists:')).toBeTruthy();
+ });
+ it('should handle error correctly when loading', () => {
+ render();
+ expect(screen.queryByRole('heading', { name: /Could not load chat/i })).toBeFalsy();
+ expect(screen.getByText('Loading message')).toBeTruthy();
+ });
+ it('should handle error correctly when these is content', () => {
+ render();
+ expect(screen.getByRole('heading', { name: /Could not load chat/i })).toBeTruthy();
+ expect(screen.queryByText('Test')).toBeFalsy();
+ });
});
diff --git a/packages/module/src/Message/Message.tsx b/packages/module/src/Message/Message.tsx
index 06778e71e..ad5809b0a 100644
--- a/packages/module/src/Message/Message.tsx
+++ b/packages/module/src/Message/Message.tsx
@@ -7,6 +7,7 @@ import React, { ReactNode } from 'react';
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import {
+ AlertProps,
Avatar,
AvatarProps,
ContentVariants,
@@ -42,6 +43,7 @@ import rehypeExternalLinks from 'rehype-external-links';
import rehypeSanitize from 'rehype-sanitize';
import { PluggableList } from 'react-markdown/lib';
import LinkMessage from './LinkMessage/LinkMessage';
+import ErrorMessage from './ErrorMessage/ErrorMessage';
export interface MessageAttachment {
/** Name of file attached to the message */
@@ -141,6 +143,8 @@ export interface MessageProps extends Omit, 'rol
additionalRehypePlugins?: PluggableList;
/** Whether to open links in message in new tab. */
openLinkInNewTab?: boolean;
+ /** Optional inline error message that can be displayed in the message */
+ error?: AlertProps;
}
export const MessageBase: React.FunctionComponent = ({
@@ -169,6 +173,7 @@ export const MessageBase: React.FunctionComponent = ({
tableProps,
openLinkInNewTab = true,
additionalRehypePlugins = [],
+ error,
...props
}: MessageProps) => {
const { beforeMainContent, afterMainContent, endContent } = extraContent || {};
@@ -225,47 +230,51 @@ export const MessageBase: React.FunctionComponent = ({
) : (
<>
{beforeMainContent && <>{beforeMainContent}>}
- ,
- code: ({ children, ...props }) => (
-
- {children}
-
- ),
- h1: (props) => ,
- h2: (props) => ,
- h3: (props) => ,
- h4: (props) => ,
- h5: (props) => ,
- h6: (props) => ,
- blockquote: (props) => ,
- ul: (props) => ,
- ol: (props) => ,
- li: (props) => ,
- table: (props) => ,
- tbody: (props) => ,
- thead: (props) => ,
- tr: (props) => ,
- td: (props) => {
- // Conflicts with Td type
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { width, ...rest } = props;
- return ;
- },
- th: (props) => ,
- img: (props) => ,
- a: (props) => (
-
- {props.children}
-
- )
- }}
- remarkPlugins={[remarkGfm]}
- rehypePlugins={rehypePlugins}
- >
- {content}
-
+ {error ? (
+
+ ) : (
+ ,
+ code: ({ children, ...props }) => (
+
+ {children}
+
+ ),
+ h1: (props) => ,
+ h2: (props) => ,
+ h3: (props) => ,
+ h4: (props) => ,
+ h5: (props) => ,
+ h6: (props) => ,
+ blockquote: (props) => ,
+ ul: (props) => ,
+ ol: (props) => ,
+ li: (props) => ,
+ table: (props) => ,
+ tbody: (props) => ,
+ thead: (props) => ,
+ tr: (props) => ,
+ td: (props) => {
+ // Conflicts with Td type
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { width, ...rest } = props;
+ return ;
+ },
+ th: (props) => ,
+ img: (props) => ,
+ a: (props) => (
+
+ {props.children}
+
+ )
+ }}
+ remarkPlugins={[remarkGfm]}
+ rehypePlugins={rehypePlugins}
+ >
+ {content}
+
+ )}
{afterMainContent && <>{afterMainContent}>}
>
)}