Skip to content

feat(SourcesCard): Add support for external links #499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
{
title: 'Getting started with Red Hat OpenShift',
link: '#',
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 ...'
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 ...',
isExternal: true
},
{
title: 'Azure Red Hat OpenShift documentation',
link: '#',
body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...'
body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...',
isExternal: true
},
{
title: 'OKD Documentation: Home',
link: '#',
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 ...'
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 ...',
isExternal: true
}
],
onSetPage
Expand All @@ -46,12 +49,14 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
{
title: 'Getting started with Red Hat OpenShift AI and other products',
link: '#',
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 ...'
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 ...',
isExternal: true
},
{
title: 'Azure Red Hat OpenShift documentation | Red Hat',
link: '#',
body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...'
body: 'Microsoft Azure Red Hat OpenShift allows you to deploy a production ready Red Hat OpenShift cluster in Azure ...',
isExternal: true
}
],
onSetPage
Expand All @@ -67,7 +72,8 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
{
title: 'Getting started with Red Hat OpenShift',
link: '#',
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 ...'
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 ...',
isExternal: true
}
],
onSetPage
Expand All @@ -80,14 +86,16 @@ export const MessageWithSourcesExample: React.FunctionComponent = () => {
content="Example with sources that include a title and link"
sources={{
sources: [
{ title: 'Getting started with Red Hat OpenShift', link: '#' },
{ title: 'Getting started with Red Hat OpenShift', link: '#', isExternal: true },
{
title: 'Azure Red Hat OpenShift documentation',
link: '#'
link: '#',
isExternal: true
},
{
title: 'OKD Documentation: Home',
link: '#'
link: '#',
isExternal: true
}
],
onSetPage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ To add quick actions, pass `quickResponses` to `<Message>`. This can be overridd

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.

If a source will open outside of the ChatBot window, add an external link icon via `isExternal`.

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.

```js file="./MessageWithSources.tsx"
Expand Down
5 changes: 0 additions & 5 deletions packages/module/src/SourcesCard/SourcesCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import '@testing-library/jest-dom';
import SourcesCard from './SourcesCard';

describe('SourcesCard', () => {
it('should render card', () => {
const { container } = render(<SourcesCard sources={[{ link: '' }]} />);
expect(container).toMatchSnapshot();
});

it('should render card correctly if one source with only a link is passed in', () => {
render(<SourcesCard sources={[{ link: '' }]} />);
expect(screen.getByText('1 source')).toBeTruthy();
Expand Down
16 changes: 14 additions & 2 deletions packages/module/src/SourcesCard/SourcesCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
pluralize,
Truncate
} from '@patternfly/react-core';
import { ExternalLinkSquareAltIcon } from '@patternfly/react-icons';

export interface SourcesCardProps extends CardProps {
/** Additional classes for the pagination navigation container. */
Expand All @@ -27,7 +28,7 @@ export interface SourcesCardProps extends CardProps {
/** Accessible label for the pagination component. */
paginationAriaLabel?: string;
/** Content rendered inside the paginated card */
sources: { title?: string; link: string; body?: React.ReactNode | string }[];
sources: { title?: string; link: string; body?: React.ReactNode | string; isExternal?: boolean }[];
/** Label for the English word "source" */
sourceWord?: string;
/** Plural for sourceWord */
Expand Down Expand Up @@ -78,7 +79,18 @@ const SourcesCard: React.FunctionComponent<SourcesCardProps> = ({
<span>{pluralize(sources.length, sourceWord, sourceWordPlural)}</span>
<Card className="pf-chatbot__sources-card" {...props}>
<CardTitle className="pf-chatbot__sources-card-title">
<a href={sources[page - 1].link}>{renderTitle(sources[page - 1].title)}</a>
<Button
component="a"
variant={ButtonVariant.link}
href={sources[page - 1].link}
icon={sources[page - 1].isExternal ? <ExternalLinkSquareAltIcon /> : undefined}
iconPosition="end"
isInline
rel={sources[page - 1].isExternal ? 'noreferrer' : undefined}
target={sources[page - 1].isExternal ? '_blank' : undefined}
>
{renderTitle(sources[page - 1].title)}
</Button>
</CardTitle>
{sources[page - 1].body && (
<CardBody
Expand Down

This file was deleted.

Loading