@patternfly/chatbot 2.2.0-prerelease.39 → 2.2.0-prerelease.40

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.
@@ -14,6 +14,7 @@ export interface SourcesCardProps extends CardProps {
14
14
  title?: string;
15
15
  link: string;
16
16
  body?: React.ReactNode | string;
17
+ isExternal?: boolean;
17
18
  }[];
18
19
  /** Label for the English word "source" */
19
20
  sourceWord?: string;
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
20
20
  const react_1 = __importDefault(require("react"));
21
21
  // Import PatternFly components
22
22
  const react_core_1 = require("@patternfly/react-core");
23
+ const react_icons_1 = require("@patternfly/react-icons");
23
24
  const SourcesCard = (_a) => {
24
25
  var { className, isDisabled, ofWord = 'of', paginationAriaLabel = 'Pagination', sources, sourceWord = 'source', sourceWordPlural = 'sources', toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage } = _a, props = __rest(_a, ["className", "isDisabled", "ofWord", "paginationAriaLabel", "sources", "sourceWord", "sourceWordPlural", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage"]);
25
26
  const [page, setPage] = react_1.default.useState(1);
@@ -37,7 +38,7 @@ const SourcesCard = (_a) => {
37
38
  react_1.default.createElement("span", null, (0, react_core_1.pluralize)(sources.length, sourceWord, sourceWordPlural)),
38
39
  react_1.default.createElement(react_core_1.Card, Object.assign({ className: "pf-chatbot__sources-card" }, props),
39
40
  react_1.default.createElement(react_core_1.CardTitle, { className: "pf-chatbot__sources-card-title" },
40
- react_1.default.createElement("a", { href: sources[page - 1].link }, renderTitle(sources[page - 1].title))),
41
+ react_1.default.createElement(react_core_1.Button, { component: "a", variant: react_core_1.ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? react_1.default.createElement(react_icons_1.ExternalLinkSquareAltIcon, null) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined }, renderTitle(sources[page - 1].title))),
41
42
  sources[page - 1].body && (react_1.default.createElement(react_core_1.CardBody, { className: `pf-chatbot__sources-card-body ${sources.length === 1 && 'pf-chatbot__sources-card-no-footer'}` }, sources[page - 1].body)),
42
43
  sources.length > 1 && (react_1.default.createElement(react_core_1.CardFooter, { className: "pf-chatbot__sources-card-footer-container" },
43
44
  react_1.default.createElement("div", { className: "pf-chatbot__sources-card-footer" },
@@ -18,10 +18,6 @@ const user_event_1 = __importDefault(require("@testing-library/user-event"));
18
18
  require("@testing-library/jest-dom");
19
19
  const SourcesCard_1 = __importDefault(require("./SourcesCard"));
20
20
  describe('SourcesCard', () => {
21
- it('should render card', () => {
22
- const { container } = (0, react_2.render)(react_1.default.createElement(SourcesCard_1.default, { sources: [{ link: '' }] }));
23
- expect(container).toMatchSnapshot();
24
- });
25
21
  it('should render card correctly if one source with only a link is passed in', () => {
26
22
  (0, react_2.render)(react_1.default.createElement(SourcesCard_1.default, { sources: [{ link: '' }] }));
27
23
  expect(react_2.screen.getByText('1 source')).toBeTruthy();
@@ -14,6 +14,7 @@ export interface SourcesCardProps extends CardProps {
14
14
  title?: string;
15
15
  link: string;
16
16
  body?: React.ReactNode | string;
17
+ isExternal?: boolean;
17
18
  }[];
18
19
  /** Label for the English word "source" */
19
20
  sourceWord?: string;
@@ -15,6 +15,7 @@ var __rest = (this && this.__rest) || function (s, e) {
15
15
  import React from 'react';
16
16
  // Import PatternFly components
17
17
  import { Button, ButtonVariant, Card, CardBody, CardFooter, CardTitle, Icon, pluralize, Truncate } from '@patternfly/react-core';
18
+ import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
18
19
  const SourcesCard = (_a) => {
19
20
  var { className, isDisabled, ofWord = 'of', paginationAriaLabel = 'Pagination', sources, sourceWord = 'source', sourceWordPlural = 'sources', toNextPageAriaLabel = 'Go to next page', toPreviousPageAriaLabel = 'Go to previous page', onNextClick, onPreviousClick, onSetPage } = _a, props = __rest(_a, ["className", "isDisabled", "ofWord", "paginationAriaLabel", "sources", "sourceWord", "sourceWordPlural", "toNextPageAriaLabel", "toPreviousPageAriaLabel", "onNextClick", "onPreviousClick", "onSetPage"]);
20
21
  const [page, setPage] = React.useState(1);
@@ -32,7 +33,7 @@ const SourcesCard = (_a) => {
32
33
  React.createElement("span", null, pluralize(sources.length, sourceWord, sourceWordPlural)),
33
34
  React.createElement(Card, Object.assign({ className: "pf-chatbot__sources-card" }, props),
34
35
  React.createElement(CardTitle, { className: "pf-chatbot__sources-card-title" },
35
- React.createElement("a", { href: sources[page - 1].link }, renderTitle(sources[page - 1].title))),
36
+ React.createElement(Button, { component: "a", variant: ButtonVariant.link, href: sources[page - 1].link, icon: sources[page - 1].isExternal ? React.createElement(ExternalLinkSquareAltIcon, null) : undefined, iconPosition: "end", isInline: true, rel: sources[page - 1].isExternal ? 'noreferrer' : undefined, target: sources[page - 1].isExternal ? '_blank' : undefined }, renderTitle(sources[page - 1].title))),
36
37
  sources[page - 1].body && (React.createElement(CardBody, { className: `pf-chatbot__sources-card-body ${sources.length === 1 && 'pf-chatbot__sources-card-no-footer'}` }, sources[page - 1].body)),
37
38
  sources.length > 1 && (React.createElement(CardFooter, { className: "pf-chatbot__sources-card-footer-container" },
38
39
  React.createElement("div", { className: "pf-chatbot__sources-card-footer" },
@@ -13,10 +13,6 @@ import userEvent from '@testing-library/user-event';
13
13
  import '@testing-library/jest-dom';
14
14
  import SourcesCard from './SourcesCard';
15
15
  describe('SourcesCard', () => {
16
- it('should render card', () => {
17
- const { container } = render(React.createElement(SourcesCard, { sources: [{ link: '' }] }));
18
- expect(container).toMatchSnapshot();
19
- });
20
16
  it('should render card correctly if one source with only a link is passed in', () => {
21
17
  render(React.createElement(SourcesCard, { sources: [{ link: '' }] }));
22
18
  expect(screen.getByText('1 source')).toBeTruthy();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/chatbot",
3
- "version": "2.2.0-prerelease.39",
3
+ "version": "2.2.0-prerelease.40",
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",
@@ -40,5 +40,15 @@ export const MessageWithQuickResponsesExample: React.FunctionComponent = () => (
40
40
  { id: '5', content: 'Something else', onClick: () => alert('Clicked id 5') }
41
41
  ]}
42
42
  />
43
+ <Message
44
+ name="Bot"
45
+ role="bot"
46
+ avatar={patternflyAvatar}
47
+ content="Did you clear your cache?"
48
+ quickResponses={[
49
+ { id: '1', content: 'Yes', isDisabled: true },
50
+ { id: '2', content: 'No', onClick: () => alert('Clicked no') }
51
+ ]}
52
+ />
43
53
  </>
44
54
  );
@@ -20,17 +20,20 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
20
20
  {
21
21
  title: 'Getting started with Red Hat OpenShift',
22
22
  link: '#',
23
- body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...'
23
+ body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...',
24
+ isExternal: true
24
25
  },
25
26
  {
26
27
  title: 'Azure Red Hat OpenShift documentation',
27
28
  link: '#',
28
- body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...'
29
+ body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...',
30
+ isExternal: true
29
31
  },
30
32
  {
31
33
  title: 'OKD Documentation: Home',
32
34
  link: '#',
33
- body: 'OKD is a distribution of Kubernetes optimized for continuous application development and multi-tenant deployment. OKD also serves as the upstream code base upon ...'
35
+ body: 'OKD is a distribution of Kubernetes optimized for continuous application development and multi-tenant deployment. OKD also serves as the upstream code base upon ...',
36
+ isExternal: true
34
37
  }
35
38
  ],
36
39
  onSetPage
@@ -46,12 +49,14 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
46
49
  {
47
50
  title: 'Getting started with Red Hat OpenShift AI and other products',
48
51
  link: '#',
49
- body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...'
52
+ body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...',
53
+ isExternal: true
50
54
  },
51
55
  {
52
56
  title: 'Azure Red Hat OpenShift documentation | Red Hat',
53
57
  link: '#',
54
- body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...'
58
+ body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...',
59
+ isExternal: true
55
60
  }
56
61
  ],
57
62
  onSetPage
@@ -67,7 +72,8 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
67
72
  {
68
73
  title: 'Getting started with Red Hat OpenShift',
69
74
  link: '#',
70
- body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...'
75
+ body: 'Red Hat OpenShift on IBM Cloud is a managed offering to create your own cluster of compute hosts where you can deploy and manage containerized apps on IBM Cloud ...',
76
+ isExternal: true
71
77
  }
72
78
  ],
73
79
  onSetPage
@@ -80,14 +86,16 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
80
86
  content="Example with sources that include a title and link"
81
87
  sources={{
82
88
  sources: [
83
- { title: 'Getting started with Red Hat OpenShift', link: '#' },
89
+ { title: 'Getting started with Red Hat OpenShift', link: '#', isExternal: true },
84
90
  {
85
91
  title: 'Azure Red Hat OpenShift documentation',
86
- link: '#'
92
+ link: '#',
93
+ isExternal: true
87
94
  },
88
95
  {
89
96
  title: 'OKD Documentation: Home',
90
- link: '#'
97
+ link: '#',
98
+ isExternal: true
91
99
  }
92
100
  ],
93
101
  onSetPage
@@ -142,6 +142,8 @@ To add quick actions, pass `quickResponses` to `<Message>`. This can be overridd
142
142
 
143
143
  If you are using Retrieval-Augmented Generation, you may want to display sources in a message. Passing `sources` to `<Message>` allows you to paginate between the sources you provide.
144
144
 
145
+ If a source will open outside of the ChatBot window, add an external link icon via `isExternal`.
146
+
145
147
  The API for a source requires a link at minimum, but we strongly recommend providing a more descriptive title and body description so users have enough context. The title is limited to 1 line and the body is limited to 2 lines.
146
148
 
147
149
  ```js file="./MessageWithSources.tsx"
@@ -5,11 +5,6 @@ import '@testing-library/jest-dom';
5
5
  import SourcesCard from './SourcesCard';
6
6
 
7
7
  describe('SourcesCard', () => {
8
- it('should render card', () => {
9
- const { container } = render(<SourcesCard sources={[{ link: '' }]} />);
10
- expect(container).toMatchSnapshot();
11
- });
12
-
13
8
  it('should render card correctly if one source with only a link is passed in', () => {
14
9
  render(<SourcesCard sources={[{ link: '' }]} />);
15
10
  expect(screen.getByText('1 source')).toBeTruthy();
@@ -16,6 +16,7 @@ import {
16
16
  pluralize,
17
17
  Truncate
18
18
  } from '@patternfly/react-core';
19
+ import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';
19
20
 
20
21
  export interface SourcesCardProps extends CardProps {
21
22
  /** Additional classes for the pagination navigation container. */
@@ -27,7 +28,7 @@ export interface SourcesCardProps extends CardProps {
27
28
  /** Accessible label for the pagination component. */
28
29
  paginationAriaLabel?: string;
29
30
  /** Content rendered inside the paginated card */
30
- sources: { title?: string; link: string; body?: React.ReactNode | string }[];
31
+ sources: { title?: string; link: string; body?: React.ReactNode | string; isExternal?: boolean }[];
31
32
  /** Label for the English word "source" */
32
33
  sourceWord?: string;
33
34
  /** Plural for sourceWord */
@@ -78,7 +79,18 @@ const SourcesCard: React.FunctionComponent<SourcesCardProps> = ({
78
79
  <span>{pluralize(sources.length, sourceWord, sourceWordPlural)}</span>
79
80
  <Card className="pf-chatbot__sources-card" {...props}>
80
81
  <CardTitle className="pf-chatbot__sources-card-title">
81
- <a href={sources[page - 1].link}>{renderTitle(sources[page - 1].title)}</a>
82
+ <Button
83
+ component="a"
84
+ variant={ButtonVariant.link}
85
+ href={sources[page - 1].link}
86
+ icon={sources[page - 1].isExternal ? <ExternalLinkSquareAltIcon /> : undefined}
87
+ iconPosition="end"
88
+ isInline
89
+ rel={sources[page - 1].isExternal ? 'noreferrer' : undefined}
90
+ target={sources[page - 1].isExternal ? '_blank' : undefined}
91
+ >
92
+ {renderTitle(sources[page - 1].title)}
93
+ </Button>
82
94
  </CardTitle>
83
95
  {sources[page - 1].body && (
84
96
  <CardBody
@@ -1,34 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`SourcesCard should render card 1`] = `
4
- <div>
5
- <div
6
- class="pf-chatbot__source"
7
- >
8
- <span>
9
- 1 source
10
- </span>
11
- <div
12
- class="pf-v6-c-card pf-chatbot__sources-card"
13
- data-ouia-component-id="OUIA-Generated-Card-1"
14
- data-ouia-component-type="PF6/Card"
15
- data-ouia-safe="true"
16
- id=""
17
- >
18
- <div
19
- class="pf-v6-c-card__title"
20
- >
21
- <div
22
- class="pf-v6-c-card__title-text pf-chatbot__sources-card-title"
23
- >
24
- <a
25
- href=""
26
- >
27
- Source 1
28
- </a>
29
- </div>
30
- </div>
31
- </div>
32
- </div>
33
- </div>
34
- `;