From de7f6b43c54a2c216b52ef3bfdb59d8481122ab9 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Wed, 11 Dec 2024 14:50:57 -0500 Subject: [PATCH 1/4] feat(QuickStartsTile): Add quick starts tile for messages Quick starts tile is based on the PF QuickStarts extension tile, with slightly reduced functionality (namely status tracking and shared context). The purpose of this card is simply to trigger a QuickStart in a different section of unrelated UI, so it accepts an onClick function and passes in its id when clicked. --- .../Messages/MessageWithQuickStart.tsx | 31 ++++ .../chatbot/examples/Messages/Messages.md | 11 +- .../Messages/explore-pipeline-quickstart.ts | 65 ++++++++ packages/module/src/Message/Message.test.tsx | 54 ++++++ packages/module/src/Message/Message.tsx | 27 +++ .../src/Message/QuickStarts/FallbackImg.tsx | 24 +++ .../Message/QuickStarts/QuickStartTile.scss | 25 +++ .../Message/QuickStarts/QuickStartTile.tsx | 147 +++++++++++++++++ .../QuickStartTileDescription.test.tsx | 57 +++++++ .../QuickStarts/QuickStartTileDescription.tsx | 81 +++++++++ .../QuickStarts/QuickStartTileHeader.tsx | 21 +++ ...monitor-sampleapp-quickstart-with-image.ts | 75 +++++++++ .../monitor-sampleapp-quickstart.ts | 75 +++++++++ .../module/src/Message/QuickStarts/types.ts | 154 ++++++++++++++++++ packages/module/src/main.scss | 1 + 15 files changed, 847 insertions(+), 1 deletion(-) create mode 100644 packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx create mode 100644 packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts create mode 100644 packages/module/src/Message/QuickStarts/FallbackImg.tsx create mode 100644 packages/module/src/Message/QuickStarts/QuickStartTile.scss create mode 100644 packages/module/src/Message/QuickStarts/QuickStartTile.tsx create mode 100644 packages/module/src/Message/QuickStarts/QuickStartTileDescription.test.tsx create mode 100644 packages/module/src/Message/QuickStarts/QuickStartTileDescription.tsx create mode 100644 packages/module/src/Message/QuickStarts/QuickStartTileHeader.tsx create mode 100644 packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts create mode 100644 packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts create mode 100644 packages/module/src/Message/QuickStarts/types.ts diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx new file mode 100644 index 00000000..3491cf04 --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import Message from '@patternfly/chatbot/dist/dynamic/Message'; +import patternflyAvatar from './patternfly_avatar.jpg'; +import { explorePipelinesQuickStart } from './explore-pipeline-quickstart.ts'; +import { monitorSampleAppQuickStart } from '@patternfly/chatbot/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts'; +import { QuickStart } from '@patternfly/chatbot/dist/esm/Message/QuickStarts/types'; + +export const MessageWithQuickStartExample: React.FunctionComponent = () => ( + <> + alert(id) + }} + /> + alert(id) + }} + /> + +); diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md index 7033369a..2c675107 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md @@ -39,7 +39,8 @@ import FileDetailsLabel from '@patternfly/chatbot/dist/dynamic/FileDetailsLabel' import FileDropZone from '@patternfly/chatbot/dist/dynamic/FileDropZone'; import { PreviewAttachment } from '@patternfly/chatbot/dist/dynamic/PreviewAttachment'; import ChatbotAlert from '@patternfly/chatbot/dist/dynamic/ChatbotAlert'; - +import { explorePipelinesQuickStart } from './explore-pipeline-quickstart.ts'; +import { monitorSampleAppQuickStart } from '@patternfly/chatbot/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts'; import userAvatar from './user_avatar.svg'; import squareImg from './PF-social-color-square.svg'; @@ -116,6 +117,14 @@ The API for a source requires a link at minimum, but we strongly recommend provi ``` +### Messages with quick start tiles + +[Quick start](/extensions/quick-starts/) tiles can be added to messages via the `quickStarts` prop. The quick start tile displayed below the message is based on the one included in the [PatternFly quick starts extension](https://github.com/patternfly/patternfly-quickstarts). It has slightly more limited functionality. For example, it does not track the state of the extension. However, it allows the user to pass in an additional `onSelectQuickStart` prop so that the name of the quick start can be captured on click. This can be used to trigger other behavior in your application, such as launching that quick start, in your main UI. + +```js file="./MessageWithQuickStart.tsx" + +``` + ### User messages Messages from users have a different background color to differentiate them from bot messages. You can also display a custom avatar that is uploaded by the user. You can further customize the avatar by applying an additional class or passing [PatternFly avatar props](/components/avatar) to the `` component via `avatarProps`. diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts new file mode 100644 index 00000000..4dd0faa6 --- /dev/null +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/explore-pipeline-quickstart.ts @@ -0,0 +1,65 @@ +import userAvatar from './user_avatar.svg'; + +export const explorePipelinesQuickStart = { + apiVersion: 'console.openshift.io/v1', + kind: 'QuickStarts', + metadata: { + name: 'explore-pipelines' + }, + spec: { + version: 4.7, + displayName: `Installing the Pipelines Operator`, + durationMinutes: 10, + icon: userAvatar, + description: `Install the OpenShift® Pipelines Operator to build Pipelines using Tekton.`, + prerequisites: [''], + introduction: `OpenShift® Pipelines is a cloud-native, continuous integration and continuous delivery (CI/CD) solution based on Kubernetes resources. It uses Tekton building blocks to automate deployments across multiple Kubernetes distributions by abstracting away the underlying implementation details. +* OpenShift Pipelines is a serverless CI/CD system that runs pipelines with all the required dependencies in isolated containers. +* They are designed for decentralized teams that work on a microservice-based architecture. +* They are defined using standard Custom Resource Definitions making them extensible and easy to integrate with the existing Kubernetes tools. This enables you to scale on-demand. +* You can use OpenShift Pipelines to build images with Kubernetes tools such as Source-to-Image (S2I), Buildah, Buildpacks, and Kaniko that are portable across any Kubernetes platform. +* You can use the Developer perspective to create and manage pipelines and view logs in your namespaces. + +To start using Pipelines, install the OpenShift® Pipelines Operator on your cluster.`, + tasks: [ + { + title: `Installing the OpenShift Pipelines Operator`, + description: `### To install the OpenShift Pipelines Operator: + +1. From the **Administrator** perspective in the console navigation panel, click **Operators > OperatorHub**. +2. In the **Filter by keyword** field, type \`OpenShift Pipelines Operator\`. +3. If the tile has an Installed label, the Operator is already installed. Proceed to the next quick start to create a Pipeline. +4. Click the **tile** to open the Operator details. +5. At the top of the OpenShift Pipelines Operator panel that opens, click **Install**. +6. Fill out the Operator subscription form by selecting the channel that matches your OpenShift cluster, and then click **Install**. +7. On the **Installed Operators** page, wait for the OpenShift Pipelines Operator's status to change from **Installing** to **Succeeded**. `, + review: { + instructions: `#### To verify that the OpenShift Pipelines Operator is installed: +1. From the **Operators** section of the navigation, go to the **Installed Operators** page. +2. Verify that the **OpenShift Pipelines Operator** appears in the list of Operators. + +In the status column, is the status of the OpenShift Pipelines Operator **Succeeded**?`, + failedTaskHelp: `This task isn’t verified yet. Try the task again, or [read more](https://docs.openshift.com/container-platform/4.6/pipelines/installing-pipelines.html#op-installing-pipelines-operator-in-web-console_installing-pipelines) about this topic.` + }, + summary: { + success: `You have installed the Pipelines Operator!`, + failed: `Try the steps again.` + } + } + ], + conclusion: `You successfully installed the OpenShift Pipelines Operator! If you want to learn how to deploy an application and associate a Pipeline with it, take the Creating a Pipeline quick start.`, + nextQuickStart: [`install-app-and-associate-pipeline`], + accessReviewResources: [ + { + group: 'operators.coreos.com', + resource: 'operatorgroups', + verb: 'list' + }, + { + group: 'packages.operators.coreos.com', + resource: 'packagemanifests', + verb: 'list' + } + ] + } +}; diff --git a/packages/module/src/Message/Message.test.tsx b/packages/module/src/Message/Message.test.tsx index e6688d41..bb27fee9 100644 --- a/packages/module/src/Message/Message.test.tsx +++ b/packages/module/src/Message/Message.test.tsx @@ -3,6 +3,8 @@ import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import Message from './Message'; import userEvent from '@testing-library/user-event'; +import { monitorSampleAppQuickStart } from './QuickStarts/monitor-sampleapp-quickstart'; +import { monitorSampleAppQuickStartWithImage } from './QuickStarts/monitor-sampleapp-quickstart-with-image'; const ALL_ACTIONS = [ { label: /Good response/i }, @@ -415,4 +417,56 @@ describe('Message', () => { expect(screen.getByRole('img')).toHaveClass('test'); expect(screen.getByRole('img')).toHaveClass('pf-chatbot__message-avatar'); }); + it('should handle QuickStart tile correctly', () => { + render( + alert(id) + }} + /> + ); + expect(screen.getByRole('button', { name: 'Monitoring your sample application' })).toBeTruthy(); + expect(screen.getByRole('heading', { name: '1 Prerequisite' })).toBeTruthy(); + expect(screen.getByRole('button', { name: 'Show prerequisites' })).toBeTruthy(); + expect(screen.getByRole('button', { name: 'Start' })).toBeTruthy(); + }); + it('should handle click on QuickStart tile correctly', async () => { + const spy = jest.fn(); + render( + spy(id) + }} + /> + ); + await userEvent.click(screen.getByRole('button', { name: 'Monitoring your sample application' })); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith(monitorSampleAppQuickStart.metadata.name); + }); + it('should handle QuickStart tile with image correctly', async () => { + const spy = jest.fn(); + render( + spy(id) + }} + /> + ); + expect(screen.getAllByRole('img')[1]).toHaveAttribute('src', 'test.png'); + }); }); diff --git a/packages/module/src/Message/Message.tsx b/packages/module/src/Message/Message.tsx index 4a507000..1166f7b4 100644 --- a/packages/module/src/Message/Message.tsx +++ b/packages/module/src/Message/Message.tsx @@ -25,6 +25,8 @@ import SourcesCard, { SourcesCardProps } from '../SourcesCard'; import ListItemMessage from './ListMessage/ListItemMessage'; import UnorderedListMessage from './ListMessage/UnorderedListMessage'; import OrderedListMessage from './ListMessage/OrderedListMessage'; +import QuickStartTile from './QuickStarts/QuickStartTile'; +import { QuickStart, QuickstartAction } from './QuickStarts/types'; export interface QuickResponse extends Omit { content: string; @@ -89,6 +91,19 @@ export interface MessageProps extends Omit, 'rol hasRoundAvatar?: boolean; /** Any additional props applied to the avatar, for additional customization */ avatarProps?: Omit; + /** Props for QuickStart card */ + quickStarts?: { + quickStart: QuickStart; + onSelectQuickStart: (id?: string) => void; + minuteWord?: string; + minuteWordPlural?: string; + prerequisiteWord?: string; + prerequisiteWordPlural?: string; + quickStartButtonAriaLabel?: string; + className?: string; + onClick?: () => void; + action?: QuickstartAction; + }; } export const Message: React.FunctionComponent = ({ @@ -108,6 +123,7 @@ export const Message: React.FunctionComponent = ({ attachments, hasRoundAvatar = true, avatarProps, + quickStarts, ...props }: MessageProps) => { let avatarClassName; @@ -165,6 +181,17 @@ export const Message: React.FunctionComponent = ({ )} {!isLoading && sources && } + {quickStarts && quickStarts.quickStart && ( + + )} {!isLoading && actions && } {!isLoading && quickResponses && ( = ({ src, alt, className, fallback }) => { + const [isSrcValid, setIsSrcValid] = React.useState(true); + + if (src && isSrcValid) { + return {alt} setIsSrcValid(false)} />; + } + + return <>{fallback}; +}; + +export default FallbackImg; diff --git a/packages/module/src/Message/QuickStarts/QuickStartTile.scss b/packages/module/src/Message/QuickStarts/QuickStartTile.scss new file mode 100644 index 00000000..7eef5d4a --- /dev/null +++ b/packages/module/src/Message/QuickStarts/QuickStartTile.scss @@ -0,0 +1,25 @@ +.pf-chatbot__quickstarts-tile { + min-width: 360px; + max-width: 650px; + width: 100%; + + @media screen and (max-width: 700px) { + max-width: 100%; + min-width: initial; + } + // some icons provided to catalog tiles might have no defined height/width. Without this style, in those cases + // the icons would have a height and width of 0. + .pf-v6-c-card__header-main { + .pf-v6-c-icon__content { + display: contents; + } + } +} + +.pf-v6-theme-dark { + .pf-chatbot__quickstarts-tile { + .pfext-catalog-item-icon__img { + filter: brightness(1.5) invert(1) hue-rotate(180deg) saturate(4); + } + } +} diff --git a/packages/module/src/Message/QuickStarts/QuickStartTile.tsx b/packages/module/src/Message/QuickStarts/QuickStartTile.tsx new file mode 100644 index 00000000..251d5c81 --- /dev/null +++ b/packages/module/src/Message/QuickStarts/QuickStartTile.tsx @@ -0,0 +1,147 @@ +import * as React from 'react'; +import RocketIcon from '@patternfly/react-icons/dist/js/icons/rocket-icon'; +import OutlinedBookmarkIcon from '@patternfly/react-icons/dist/js/icons/outlined-bookmark-icon'; +import { + Card, + CardBody, + CardHeader, + CardFooter, + CardTitle, + Icon, + Button, + Flex, + Stack, + Label, + pluralize +} from '@patternfly/react-core'; +import OutlinedClockIcon from '@patternfly/react-icons/dist/js/icons/outlined-clock-icon'; +import QuickStartTileHeader from './QuickStartTileHeader'; +import QuickStartTileDescription from './QuickStartTileDescription'; +import { QuickStart, QuickstartAction } from './types'; +import FallbackImg from './FallbackImg'; + +export const camelize = (str: string) => + str.replace(/(?:^\w|[A-Z]|\b\w|\s+)/g, function (match, index) { + if (+match === 0) { + return ''; + } // or if (/\s+/.test(match)) for white spaces + return index === 0 ? match.toLowerCase() : match.toUpperCase(); + }); + +export interface QuickStartTileProps { + /** ClassName applied to the card */ + className?: string; + /** The quickstart object triggered by this tile */ + quickStart: QuickStart; + /** Event handler attached to the tile */ + onClick?: () => void; + /** Action config for button rendered next to title */ + action?: QuickstartAction; + /** Callback that returns active quick start value when clicked */ + onSelectQuickStart: (id?: string) => void; + /** Label for the English word "minute". */ + minuteWord?: string; + /** Label for the English word "minutes". */ + minuteWordPlural?: string; + /** Label for the English word "Prerequisite" */ + prerequisiteWord?: string; + /** Label for the English word "Prerequisites" */ + prerequisiteWordPlural?: string; + /** Aria-label for the quick start description button */ + quickStartButtonAriaLabel?: string; +} + +const QuickStartTile: React.FC = ({ + className, + quickStart, + onClick, + onSelectQuickStart, + minuteWord = 'minute', + minuteWordPlural = 'minutes', + prerequisiteWord, + prerequisiteWordPlural, + quickStartButtonAriaLabel, + action +}) => { + const { + metadata: { name: id }, + spec: { icon, displayName, description, durationMinutes, prerequisites, link, type } + } = quickStart; + + let quickStartIcon: React.ReactNode; + if (typeof icon === 'object') { + quickStartIcon = {icon}; + } else { + quickStartIcon = ( + + } /> + + ); + } + + const onSelect = () => { + if (!link) { + onSelectQuickStart(id); + } else { + window.open(link.href, '_blank', 'noopener,noreferrer'); + } + onClick && onClick(); + }; + + const ActionIcon = action?.icon || OutlinedBookmarkIcon; + const additionalAction = action ? ( + + + + ); +}; + +export default QuickStartTile; diff --git a/packages/module/src/Message/QuickStarts/QuickStartTileDescription.test.tsx b/packages/module/src/Message/QuickStarts/QuickStartTileDescription.test.tsx new file mode 100644 index 00000000..3c0c5d9b --- /dev/null +++ b/packages/module/src/Message/QuickStarts/QuickStartTileDescription.test.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import userEvent from '@testing-library/user-event'; +import { monitorSampleAppQuickStart } from './monitor-sampleapp-quickstart'; +import QuickStartTileDescription, { pluralizeWord } from './QuickStartTileDescription'; + +describe('pluralizeWord function', () => { + it('should render no plural correctly', () => { + expect(pluralizeWord(2, 'pizza')).toBe('pizzas'); + }); +}); + +describe('QuickStart tile description', () => { + it('should render no prereqs correctly', () => { + render(); + expect(screen.queryByRole('heading')).toBeFalsy(); + }); + it('should render singular prereq correctly', () => { + render( + + ); + expect(screen.getByRole('heading', { name: /1 Prerequisite/i })).toBeTruthy(); + expect(screen.getByRole('button', { name: /Show prerequisite/i })).toBeTruthy(); + }); + it('should render plural prereq correctly', () => { + render( + + ); + expect(screen.getByRole('heading', { name: /2 Prerequisites/i })).toBeTruthy(); + expect(screen.getByRole('button', { name: /Show prerequisites/i })).toBeTruthy(); + }); + it('should be able to click prereqs link', async () => { + render( + + ); + const button = screen.getByRole('button', { name: /Show prerequisites/i }); + expect(screen.queryByRole('dialog', { name: /Prerequisite/i })).toBeFalsy(); + await userEvent.click(button); + + expect(screen.getByRole('dialog', { name: /Prerequisite/i })).toBeTruthy(); + expect(screen.getByRole('button', { name: /Close/i })).toBeTruthy(); + expect(screen.getByText(/You completed the "Getting started with a sample" quick start./i)).toBeTruthy(); + }); +}); diff --git a/packages/module/src/Message/QuickStarts/QuickStartTileDescription.tsx b/packages/module/src/Message/QuickStarts/QuickStartTileDescription.tsx new file mode 100644 index 00000000..5f47f3eb --- /dev/null +++ b/packages/module/src/Message/QuickStarts/QuickStartTileDescription.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { Button, Flex, pluralize, Popover } from '@patternfly/react-core'; +import InfoCircleIcon from '@patternfly/react-icons/dist/js/icons/info-circle-icon'; + +interface QuickStartTileDescriptionProps { + /** QuickStart description */ + description: string; + /** QuickStart prerequisites */ + prerequisites?: string[]; + /** Label for the English word "Prerequisite" */ + prerequisiteWord?: string; + /** Label for the English word "Prerequisites" */ + prerequisiteWordPlural?: string; + /** Aria-label for the quick start button */ + quickStartButtonAriaLabel?: string; +} + +/** This function is a helper for pluralizing strings stolen from React. + * + * @param {number} i The quantity of the string you want to pluralize + * @param {string} singular The singular version of the string + * @param {string} plural The change to the string that should occur if the quantity is not equal to 1. + * Defaults to adding an 's'. + */ +export function pluralizeWord(i: number, singular: string, plural?: string) { + if (!plural) { + plural = `${singular}s`; + } + return `${i === 1 ? singular : plural}`; +} + +const QuickStartTileDescription: React.FC = ({ + description, + prerequisites, + prerequisiteWord = 'Prerequisite', + prerequisiteWordPlural = 'Prerequisites', + quickStartButtonAriaLabel = 'Show prerequisites' +}) => { + const prereqs = prerequisites?.filter((p) => p); + const buttonRef = React.useRef(null); + const pluralizedPrereq = pluralizeWord(prereqs?.length || 0, prerequisiteWord, prerequisiteWordPlural); + return ( + <> + {description} + {prereqs && prereqs.length > 0 && ( + +
{pluralize(prereqs.length, prerequisiteWord, prerequisiteWordPlural)}
+ + +
    + {prereqs.map((prerequisite, index) => ( + // eslint-disable-next-line react/no-array-index-key +
  • {prerequisite}
  • + ))} +
+ + } + /> +
+ )} + + ); +}; +export default QuickStartTileDescription; diff --git a/packages/module/src/Message/QuickStarts/QuickStartTileHeader.tsx b/packages/module/src/Message/QuickStarts/QuickStartTileHeader.tsx new file mode 100644 index 00000000..6315f293 --- /dev/null +++ b/packages/module/src/Message/QuickStarts/QuickStartTileHeader.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { Button, Flex } from '@patternfly/react-core'; + +interface QuickStartTileHeaderProps { + /** Name for the header */ + name: string; + /** Id for the QuickStart */ + quickStartId?: string; + /** Callback for when the name of the QuickStart is clicked */ + onSelect: (e: React.FormEvent | React.MouseEvent) => void; +} + +const QuickStartTileHeader: React.FC = ({ name, quickStartId, onSelect }) => ( + + + +); + +export default QuickStartTileHeader; diff --git a/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts b/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts new file mode 100644 index 00000000..a35d4b83 --- /dev/null +++ b/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart-with-image.ts @@ -0,0 +1,75 @@ +export const monitorSampleAppQuickStartWithImage = { + apiVersion: 'console.openshift.io/v1', + kind: 'QuickStarts', + metadata: { + name: 'monitor-sampleapp' + }, + spec: { + icon: 'test.png', // this is only difference + version: 4.7, + displayName: 'Monitoring your sample application', + durationMinutes: 10, + description: `Now that you’ve created a sample application and added health checks, let’s monitor your application.`, + prerequisites: [`You completed the "Getting started with a sample" quick start.`], + introduction: `### This quick start shows you how to monitor your sample application. +You should have previously created the **sample-app** application and **nodejs-sample** deployment via the **Get started with a sample** quick start. If you haven't, you may be able to follow these tasks with any existing deployment.`, + tasks: [ + { + title: `Viewing the monitoring details of your sample application`, + description: `### To view the details of your sample application: +1. Go to the project your sample application was created in. +2. In the ** Developer** perspective, go to **Topology** view. +3. Click on the **nodejs-sample** deployment to view its details. +4. Click on the **Monitoring** tab in the side panel. +You can see context sensitive metrics and alerts in the **Monitoring** tab.`, + review: { + instructions: `#### To verify you can view the monitoring information: +1. Do you see a **Metrics** accordion in the side panel? +2. Do you see a **View monitoring dashboard** link in the **Metrics** accordion? +3. Do you see three charts in the **Metrics** accordion: **CPU Usage**, **Memory Usage** and **Receive Bandwidth**?`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how you can monitor your sample app!`, + failed: `Try the steps again.` + } + }, + { + title: `Viewing your project monitoring dashboard`, + description: `### To view the project monitoring dashboard in the context of **nodejs-sample**: +1. Click on the **View monitoring dashboard** link in the side panel. +2. You can change the **Time Range** and **Refresh Interval** of the dashboard. +3. You can change the context of the dashboard as well by clicking on the drop-down list. Select a specific workload or **All Workloads** to view the dashboard in the context of the entire project.`, + review: { + instructions: `#### To verify that you are able to view the monitoring dashboard: +Do you see metrics charts in the dashboard?`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how to view the dashboard in the context of your sample app!`, + failed: `Try the steps again.` + } + }, + { + title: `Viewing custom metrics`, + description: `### To view custom metrics: +1. Click on the **Metrics** tab of the **Monitoring** page. +2. Click the **Select Query** drop-down list to see the available queries. +3. Click on **Filesystem Usage** from the list to run the query.`, + review: { + instructions: `#### Verify you can see the chart associated with the query: +Do you see a chart displayed with filesystem usage for your project? Note: select **Custom Query** from the dropdown to create and run a custom query utilizing PromQL. +`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how to run a query!`, + failed: `Try the steps again.` + } + } + ], + conclusion: `You have learned how to access workload monitoring and metrics!`, + + nextQuickStart: [``] + } +}; diff --git a/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts b/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts new file mode 100644 index 00000000..ecd2492e --- /dev/null +++ b/packages/module/src/Message/QuickStarts/monitor-sampleapp-quickstart.ts @@ -0,0 +1,75 @@ +export const monitorSampleAppQuickStart = { + apiVersion: 'console.openshift.io/v1', + kind: 'QuickStarts', + metadata: { + name: 'monitor-sampleapp' + }, + spec: { + version: 4.7, + displayName: 'Monitoring your sample application', + durationMinutes: 10, + icon: '', + description: `Now that you’ve created a sample application and added health checks, let’s monitor your application.`, + prerequisites: [`You completed the "Getting started with a sample" quick start.`], + introduction: `### This quick start shows you how to monitor your sample application. +You should have previously created the **sample-app** application and **nodejs-sample** deployment via the **Get started with a sample** quick start. If you haven't, you may be able to follow these tasks with any existing deployment.`, + tasks: [ + { + title: `Viewing the monitoring details of your sample application`, + description: `### To view the details of your sample application: +1. Go to the project your sample application was created in. +2. In the ** Developer** perspective, go to **Topology** view. +3. Click on the **nodejs-sample** deployment to view its details. +4. Click on the **Monitoring** tab in the side panel. +You can see context sensitive metrics and alerts in the **Monitoring** tab.`, + review: { + instructions: `#### To verify you can view the monitoring information: +1. Do you see a **Metrics** accordion in the side panel? +2. Do you see a **View monitoring dashboard** link in the **Metrics** accordion? +3. Do you see three charts in the **Metrics** accordion: **CPU Usage**, **Memory Usage** and **Receive Bandwidth**?`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how you can monitor your sample app!`, + failed: `Try the steps again.` + } + }, + { + title: `Viewing your project monitoring dashboard`, + description: `### To view the project monitoring dashboard in the context of **nodejs-sample**: +1. Click on the **View monitoring dashboard** link in the side panel. +2. You can change the **Time Range** and **Refresh Interval** of the dashboard. +3. You can change the context of the dashboard as well by clicking on the drop-down list. Select a specific workload or **All Workloads** to view the dashboard in the context of the entire project.`, + review: { + instructions: `#### To verify that you are able to view the monitoring dashboard: +Do you see metrics charts in the dashboard?`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how to view the dashboard in the context of your sample app!`, + failed: `Try the steps again.` + } + }, + { + title: `Viewing custom metrics`, + description: `### To view custom metrics: +1. Click on the **Metrics** tab of the **Monitoring** page. +2. Click the **Select Query** drop-down list to see the available queries. +3. Click on **Filesystem Usage** from the list to run the query.`, + review: { + instructions: `#### Verify you can see the chart associated with the query: +Do you see a chart displayed with filesystem usage for your project? Note: select **Custom Query** from the dropdown to create and run a custom query utilizing PromQL. +`, + failedTaskHelp: `This task isn’t verified yet. Try the task again.` + }, + summary: { + success: `You have learned how to run a query!`, + failed: `Try the steps again.` + } + } + ], + conclusion: `You have learned how to access workload monitoring and metrics!`, + + nextQuickStart: [``] + } +}; diff --git a/packages/module/src/Message/QuickStarts/types.ts b/packages/module/src/Message/QuickStarts/types.ts new file mode 100644 index 00000000..a982d1a9 --- /dev/null +++ b/packages/module/src/Message/QuickStarts/types.ts @@ -0,0 +1,154 @@ +import { ButtonProps } from '@patternfly/react-core'; + +// These types are all from the QuickStart extension. +// We want to ensure parity, so be careful when adjusting these. +export interface AccessReviewResourceAttributes { + group?: string; + resource?: string; + subresource?: string; + verb?: K8sVerb; + name?: string; + namespace?: string; +} + +export type K8sVerb = 'create' | 'get' | 'list' | 'update' | 'patch' | 'delete' | 'deletecollection' | 'watch'; + +export interface QuickStart { + apiVersion?: string; + kind?: string; + metadata: ObjectMetadata; + spec: QuickStartSpec; +} + +export interface ObjectMetadata { + name: string; + annotations?: { [key: string]: string }; + clusterName?: string; + creationTimestamp?: string; + deletionGracePeriodSeconds?: number; + deletionTimestamp?: string; + finalizers?: string[]; + generateName?: string; + generation?: number; + labels?: { [key: string]: string }; + managedFields?: any[]; + namespace?: string; + ownerReferences?: OwnerReference[]; + resourceVersion?: string; + uid?: string; + // language can be: en + language?: string; + // country can be: US + country?: string; + // locale is a combination of language and country, for example: en_US + locale?: string; + // anything else to custom define + [key: string]: any; +} + +export interface OwnerReference { + name: string; + kind: string; + uid: string; + apiVersion: string; + controller?: boolean; + blockOwnerDeletion?: boolean; +} + +export interface QuickStartTask { + title?: string; + description?: string; + review?: QuickStartTaskReview; + summary?: QuickStartTaskSummary; + proc?: string; +} + +export interface QuickStartTaskReview { + instructions?: string; + failedTaskHelp?: string; +} + +export interface QuickStartTaskSummary { + success?: string; + failed?: string; +} + +export interface QuickstartAction { + /** Screen reader aria label. */ + 'aria-label': string; + /** Icon to be rendered as a plain button, by default Bookmark outlined will be used. */ + icon?: React.ComponentType; + /** Callback with synthetic event parameter. */ + onClick?: (e: React.SyntheticEvent) => void; + /** Additional button props to be rendered as extra props. */ + buttonProps?: ButtonProps; +} + +export interface QuickStart { + apiVersion?: string; + kind?: string; + metadata: ObjectMetadata; + spec: QuickStartSpec; +} + +export interface QuickStartSpec { + version?: number; + displayName: string; + durationMinutes?: number; + icon: React.ReactNode; + description: string; + prerequisites?: string[]; + introduction?: string; + tasks?: QuickStartTask[]; + conclusion?: string; + nextQuickStart?: string[]; + accessReviewResources?: AccessReviewResourceAttributes[]; + link?: QuickStartExternal; + type?: QuickStartType; +} + +export interface QuickStartTask { + title?: string; + description?: string; + review?: QuickStartTaskReview; + summary?: QuickStartTaskSummary; + proc?: string; +} + +export interface QuickStartTaskReview { + instructions?: string; + failedTaskHelp?: string; +} + +export interface QuickStartTaskSummary { + success?: string; + failed?: string; +} + +export type AllQuickStartStates = Record; + +export type QuickStartState = Record; + +export enum QuickStartStatus { + COMPLETE = 'Complete', + IN_PROGRESS = 'In Progress', + NOT_STARTED = 'Not started' +} + +export enum QuickStartTaskStatus { + INIT = 'Initial', + VISITED = 'Visited', + REVIEW = 'Review', + SUCCESS = 'Success', + FAILED = 'Failed' +} + +export interface QuickStartExternal { + href: string; + text?: string; +} + +export interface QuickStartType { + text: string; + color?: 'green' | 'purple' | 'grey' | 'blue' | 'orange' | 'red' | 'teal' | 'orangered' | 'yellow'; +} diff --git a/packages/module/src/main.scss b/packages/module/src/main.scss index 32528581..d55d9b56 100644 --- a/packages/module/src/main.scss +++ b/packages/module/src/main.scss @@ -18,6 +18,7 @@ @import './Message/TextMessage/TextMessage'; @import './Message/ListMessage/ListMessage'; @import './Message/MessageLoading'; +@import './Message/QuickStarts/QuickStartTile'; @import './MessageBar/MessageBar'; @import './MessageBox/MessageBox'; @import './MessageBox/JumpButton'; From 40702964e96f517108eef863e279427f21fd4270 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Mon, 6 Jan 2025 12:12:31 -0500 Subject: [PATCH 2/4] Update packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com> --- .../chatbot/examples/Messages/MessageWithQuickStart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx index 3491cf04..1bb91089 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx @@ -11,7 +11,7 @@ export const MessageWithQuickStartExample: React.FunctionComponent = () => ( name="Bot" role="bot" avatar={patternflyAvatar} - content="Text-based message from a bot with QuickStart tile." + content="Text-based bot message with a quick start tile." quickStarts={{ quickStart: explorePipelinesQuickStart as QuickStart, onSelectQuickStart: (id) => alert(id) From c97a3cc8ed161982e660975edb741a31a5b03606 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Mon, 6 Jan 2025 12:12:38 -0500 Subject: [PATCH 3/4] Update packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com> --- .../chatbot/examples/Messages/MessageWithQuickStart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx index 1bb91089..28276930 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/MessageWithQuickStart.tsx @@ -21,7 +21,7 @@ export const MessageWithQuickStartExample: React.FunctionComponent = () => ( name="Bot" role="bot" avatar={patternflyAvatar} - content="Text-based message from a bot with QuickStart tile that includes prerequisites and a default icon." + content="Text-based bot message with a quick start tile that includes prerequisites and a default icon." quickStarts={{ quickStart: monitorSampleAppQuickStart, onSelectQuickStart: (id) => alert(id) From 93660e47f8eae017669fb3e78cf07d50ce9318ca Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Mon, 6 Jan 2025 12:14:11 -0500 Subject: [PATCH 4/4] Update packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md Co-authored-by: Erin Donehoo <105813956+edonehoo@users.noreply.github.com> --- .../content/extensions/chatbot/examples/Messages/Messages.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md index 2c675107..052b96f4 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/Messages.md @@ -119,7 +119,9 @@ The API for a source requires a link at minimum, but we strongly recommend provi ### Messages with quick start tiles -[Quick start](/extensions/quick-starts/) tiles can be added to messages via the `quickStarts` prop. The quick start tile displayed below the message is based on the one included in the [PatternFly quick starts extension](https://github.com/patternfly/patternfly-quickstarts). It has slightly more limited functionality. For example, it does not track the state of the extension. However, it allows the user to pass in an additional `onSelectQuickStart` prop so that the name of the quick start can be captured on click. This can be used to trigger other behavior in your application, such as launching that quick start, in your main UI. +[Quick start](/extensions/quick-starts/) tiles can be added to messages via the `quickStarts` prop. Users can initiate the quick start from a link within the message tile. + +The quick start tile displayed below the message is based on the tile included in the [PatternFly quick starts extension](https://github.com/patternfly/patternfly-quickstarts), but with slightly more limited functionality. For example, it does not track the state of the extension. However, it supports an additional `onSelectQuickStart` prop, so that the name of the quick start can be captured on click. This can be used to trigger other behavior in your application, such as launching that quick start in your main UI. ```js file="./MessageWithQuickStart.tsx"