From 3924732b9327d15eab85d73fe587afd8f70db774 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Thu, 24 Jul 2025 11:03:16 -0400 Subject: [PATCH 1/7] chore(docs): Add demo for live progress summary card Adding demo for card as custom component. It is not something we ship, but providing proof we can enable complex card behavior as an injected component. --- .../chatbot/examples/Messages/Messages.md | 1 + .../Messages/UserMessageWithExtraContent.tsx | 270 +++++++++++++++++- 2 files changed, 260 insertions(+), 11 deletions(-) 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 981464fdf..493aefd92 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 @@ -30,6 +30,7 @@ propComponents: sortValue: 3 --- +import { ArrowRightIcon, CheckCircleIcon } from '@patternfly/react-icons'; import Message from '@patternfly/chatbot/dist/dynamic/Message'; import MessageDivider from '@patternfly/chatbot/dist/dynamic/MessageDivider'; import { rehypeCodeBlockToggle } from '@patternfly/chatbot/dist/esm/Message/Plugins/rehypeCodeBlockToggle'; diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx index db5acf761..7a50ef03b 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx @@ -1,8 +1,36 @@ -import { Fragment, FunctionComponent } from 'react'; - +import { Fragment, FunctionComponent, useState } from 'react'; import Message from '@patternfly/chatbot/dist/dynamic/Message'; import userAvatar from './user_avatar.svg'; -import { Alert, Badge, Button, Card, CardBody, CardFooter, CardTitle } from '@patternfly/react-core'; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionToggle, + Alert, + Badge, + Button, + Card, + CardBody, + CardFooter, + CodeBlock, + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, + HelperText, + HelperTextItem, + Progress, + ProgressMeasureLocation, + Flex, + FlexItem, + CardTitle, + CardHeader, + CardExpandableContent, + Spinner, + CodeBlockCode +} from '@patternfly/react-core'; +import { ArrowRightIcon, CheckCircleIcon } from '@patternfly/react-icons'; +import React from 'react'; const UserActionEndContent = () => { // eslint-disable-next-line no-console @@ -17,14 +45,6 @@ const UserActionEndContent = () => { ); }; -const CardInformationAfterMainContent = () => ( - - This is content card after main content - Body - Footer - -); - const BeforeMainContent = () => (
@@ -36,6 +56,224 @@ const BeforeMainContent = () => (
); +const CardInformationAfterMainContent = () => ( + + This is content card after main content + Body + Footer + +); + +const LiveProgressSummaryCard = () => { + const [isCardExpanded, setIsCardExpanded] = useState(false); + const [isAccordionExpanded, setIsAccordionExpanded] = useState('deploying-toggle'); + + const onExpandCard = (_event: React.MouseEvent) => { + setIsCardExpanded(!isCardExpanded); + }; + + const onExpandAccordion = (id: string) => { + if (id === isAccordionExpanded) { + setIsAccordionExpanded(''); + } else { + setIsAccordionExpanded(id); + } + }; + + const renderCodeBlock = (initialWord: string) => ( + + + {`${initialWord} openshift-apiserver operator... +${initialWord} openshift-sdn operator... +${initialWord} openshift-ingress operator...`} + + + ); + + return ( + // eslint-disable-next-line no-console + + + + + + OpenShift cluster installation + + + + + + Deploying cluster operators + + + + + About 23 minutes left + + + + } + /> + + + + + + +
+ + + { + onExpandAccordion('installing-toggle'); + }} + id="installing-toggle" + > + + + + + Installing cluster bootstrap + + + + {renderCodeBlock('Installing')} + + + + { + onExpandAccordion('setup-toggle'); + }} + id="setup-toggle" + > + + + + + Control plane setup + + + + {renderCodeBlock('Setting up')} + + + + { + onExpandAccordion('deploying-toggle'); + }} + id="deploying-toggle" + > + + + + + Deploying cluster operators + + + + {renderCodeBlock('Deploying')} + + + + { + onExpandAccordion('finalizing-toggle'); + }} + id="finalizing-toggle" + disabled + > + + {/* Empty space to maintain consistent alignment */} + Finalizing installation + + + + {renderCodeBlock('Finalizing')} + + + +
+
+ + + +
+ ); +}; + export const UserMessageWithExtraContent: FunctionComponent = () => ( <> ( endContent: }} /> + + }} + /> ); From b5ce962ddc513dd63066fdded144cdf32dd70a38 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Tue, 5 Aug 2025 16:50:11 -0400 Subject: [PATCH 2/7] Address feedback --- .../examples/Messages/UserMessageWithExtraContent.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx index 7a50ef03b..baf39db00 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx @@ -152,7 +152,7 @@ ${initialWord} openshift-ingress operator...`} > - + Installing cluster bootstrap @@ -182,7 +182,7 @@ ${initialWord} openshift-ingress operator...`} > - + Control plane setup @@ -212,7 +212,7 @@ ${initialWord} openshift-ingress operator...`} > - + Deploying cluster operators @@ -239,7 +239,6 @@ ${initialWord} openshift-ingress operator...`} onExpandAccordion('finalizing-toggle'); }} id="finalizing-toggle" - disabled > {/* Empty space to maintain consistent alignment */} From 52a4515633c9a23912e9f1883b7b9dec224a39f2 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Wed, 6 Aug 2025 14:09:08 -0400 Subject: [PATCH 3/7] chore(docs): Add installation simulation Assisted-by: Cursor --- .../Messages/UserMessageWithExtraContent.tsx | 466 +++++++++++------- 1 file changed, 277 insertions(+), 189 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx index baf39db00..8641c95e5 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx @@ -1,4 +1,4 @@ -import { Fragment, FunctionComponent, useState } from 'react'; +import { Fragment, FunctionComponent, useState, useEffect } from 'react'; import Message from '@patternfly/chatbot/dist/dynamic/Message'; import userAvatar from './user_avatar.svg'; import { @@ -30,7 +30,6 @@ import { CodeBlockCode } from '@patternfly/react-core'; import { ArrowRightIcon, CheckCircleIcon } from '@patternfly/react-icons'; -import React from 'react'; const UserActionEndContent = () => { // eslint-disable-next-line no-console @@ -45,6 +44,14 @@ const UserActionEndContent = () => { ); }; +const CardInformationAfterMainContent = () => ( + + This is content card after main content + Body + Footer + +); + const BeforeMainContent = () => (
@@ -56,23 +63,126 @@ const BeforeMainContent = () => (
); -const CardInformationAfterMainContent = () => ( - - This is content card after main content - Body - Footer - -); +interface Stage { + id: string; + name: string; + startProgress: number; + endProgress: number; +} const LiveProgressSummaryCard = () => { const [isCardExpanded, setIsCardExpanded] = useState(false); - const [isAccordionExpanded, setIsAccordionExpanded] = useState('deploying-toggle'); + const [isAccordionExpanded, setIsAccordionExpanded] = useState('installing-toggle'); + const [progress, setProgress] = useState(15); + const [isSimulationRunning, setIsSimulationRunning] = useState(false); + const [userManuallyExpandedAccordion, setUserManuallyExpandedAccordion] = useState(false); + + const stages: Stage[] = [ + { + id: 'installing-toggle', + name: 'Installing cluster bootstrap', + startProgress: 0, + endProgress: 25 + }, + { + id: 'setup-toggle', + name: 'Control plane setup', + startProgress: 25, + endProgress: 45 + }, + { + id: 'deploying-toggle', + name: 'Deploying cluster operators', + startProgress: 45, + endProgress: 85 + }, + { + id: 'finalizing-toggle', + name: 'Finalizing installation', + startProgress: 85, + endProgress: 100 + } + ]; + + const getCurrentStage = () => + stages.find((stage) => progress >= stage.startProgress && progress < stage.endProgress) || + stages[stages.length - 1]; + + const getTimeRemaining = () => { + const remainingProgress = 100 - progress; + const estimatedMinutes = Math.max(1, Math.round((remainingProgress / 100) * 30)); // 30 minutes total simulation + return `About ${estimatedMinutes} minute${estimatedMinutes !== 1 ? 's' : ''} left`; + }; + + const getCurrentStageName = () => { + const currentStage = getCurrentStage(); + return currentStage.name; + }; + + const getStageStatus = (stage: Stage) => { + if (progress >= stage.endProgress) { + return 'completed'; + } + if (progress >= stage.startProgress) { + return 'in-progress'; + } + return 'pending'; + }; + + const renderStageIcon = (stage: Stage) => { + const status = getStageStatus(stage); + + if (status === 'completed') { + return ; + } else if (status === 'in-progress') { + return ; + } else { + return
{/* Empty space for pending stages */}
; + } + }; + + // Auto-increment progress when simulation is running + useEffect(() => { + let interval; + + if (isSimulationRunning && progress < 100) { + interval = setInterval(() => { + setProgress((prev) => { + const increment = Math.random() * 2 + 0.5; // Random increment between 0.5-2.5% + const newProgress = Math.min(prev + increment, 100); + + // Stop simulation when complete + if (newProgress >= 100) { + setIsSimulationRunning(false); + setUserManuallyExpandedAccordion(false); // Reset manual override when simulation completes + } + + return newProgress; + }); + }, 800); + } + + return () => { + if (interval) { + clearInterval(interval); + } + }; + }, [isSimulationRunning, progress]); + + // Auto-expand accordion to show current stage (only if user hasn't manually overridden) + useEffect(() => { + if (isSimulationRunning && !userManuallyExpandedAccordion) { + setIsAccordionExpanded(getCurrentStage().id); + } + }, [progress, isSimulationRunning, userManuallyExpandedAccordion]); const onExpandCard = (_event: React.MouseEvent) => { setIsCardExpanded(!isCardExpanded); }; const onExpandAccordion = (id: string) => { + setUserManuallyExpandedAccordion(true); + if (id === isAccordionExpanded) { setIsAccordionExpanded(''); } else { @@ -80,7 +190,38 @@ const LiveProgressSummaryCard = () => { } }; - const renderCodeBlock = (initialWord: string) => ( + const getStageContent = (stage: Stage) => { + const status = getStageStatus(stage); + + if (status === 'in-progress') { + switch (stage.id) { + case 'installing-toggle': + return `Installing bootstrap node... +Installing etcd cluster... +Installing control plane...`; + case 'setup-toggle': + return `Configuring cluster networking... +Setting up OpenShift API server... +Configuring authentication... +Setting up cluster operators...`; + case 'deploying-toggle': + return `Deploying openshift-apiserver operator... +Deploying openshift-sdn operator... +Deploying openshift-ingress operator... +`; + case 'finalizing-toggle': + return `Finalizing cluster configuration... +Running post-installation tasks... +Setting up cluster console...`; + } + } + if (status === 'pending') { + return 'Processing...'; + } + return 'Complete!'; + }; + + const renderCodeBlock = (stage: Stage) => ( { } as React.CSSProperties } > - - {`${initialWord} openshift-apiserver operator... -${initialWord} openshift-sdn operator... -${initialWord} openshift-ingress operator...`} - + {getStageContent(stage)} ); return ( - // eslint-disable-next-line no-console - - - - - - OpenShift cluster installation - - - - - - Deploying cluster operators - - - - - About 23 minutes left - - -
- } - /> - - - - - - -
- - - { - onExpandAccordion('installing-toggle'); - }} - id="installing-toggle" - > - - - - - Installing cluster bootstrap - - - - {renderCodeBlock('Installing')} - - - - { - onExpandAccordion('setup-toggle'); - }} - id="setup-toggle" - > - - - - - Control plane setup - - - - {renderCodeBlock('Setting up')} - - - - { - onExpandAccordion('deploying-toggle'); - }} - id="deploying-toggle" - > - - - - - Deploying cluster operators - - - - {renderCodeBlock('Deploying')} - - - - { - onExpandAccordion('finalizing-toggle'); - }} - id="finalizing-toggle" - > - - {/* Empty space to maintain consistent alignment */} - Finalizing installation - - - - {renderCodeBlock('Finalizing')} - - - -
-
- - - - + <> + + + + + + + + + + + + + + OpenShift cluster installation + + + + + + + {progress >= 100 ? 'Installation complete!' : getCurrentStageName()} + + + + + + {progress >= 100 ? 'Completed' : getTimeRemaining()} + + + + } + /> + + + + + + +
+ + {stages.map((stage) => ( + + { + onExpandAccordion(stage.id); + }} + id={stage.id} + > + + {renderStageIcon(stage)} + {stage.name} + + + + {renderCodeBlock(stage)} + + + ))} + +
+
+ + + +
+ ); }; From c597ee7c2b0f371d2aa17f1da629c7f8169c0305 Mon Sep 17 00:00:00 2001 From: Rebecca Alpert Date: Wed, 6 Aug 2025 17:38:08 -0400 Subject: [PATCH 4/7] Replace a couple of tokens with utility classes Also moved some vars up --- .../Messages/UserMessageWithExtraContent.tsx | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx index 8641c95e5..4f96d2bce 100644 --- a/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx +++ b/packages/module/patternfly-docs/content/extensions/chatbot/examples/Messages/UserMessageWithExtraContent.tsx @@ -235,7 +235,7 @@ Setting up cluster console...`; return ( <> - +