import { Fragment, FunctionComponent, useState, useEffect } from 'react'; import Message from '@patternfly/chatbot/dist/dynamic/Message'; import userAvatar from './user_avatar.svg'; import patternflyAvatar from '../Messages/patternfly_avatar.jpg'; import { Accordion, AccordionContent, AccordionItem, AccordionToggle, Alert, Badge, Button, ButtonVariant, Card, CardBody, CardExpandableContent, CardFooter, CardHeader, CardTitle, CodeBlock, CodeBlockCode, Content, ContentVariants, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Flex, FlexItem, HelperText, HelperTextItem, Icon, Progress, ProgressMeasureLocation, ExpandableSection, ExpandableSectionToggle, Label, Tab, Tabs, TabTitleText, Spinner } from '@patternfly/react-core'; import { ArrowCircleDownIcon, ArrowRightIcon, CheckCircleIcon, CubeIcon, CubesIcon } from '@patternfly/react-icons'; const UserActionEndContent = () => { // eslint-disable-next-line no-console const onClick = () => console.log('custom button click'); return ( ); }; const CardInformationAfterMainContent = () => ( This is content card after main content Body Footer ); const BeforeMainContent = () => (
7 24
); interface Stage { id: string; name: string; startProgress: number; endProgress: number; } const LiveProgressSummaryCard = () => { const [isCardExpanded, setIsCardExpanded] = useState(false); 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' : ''} remaining`; }; 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 { setIsAccordionExpanded(id); } }; 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) => ( {getStageContent(stage)} ); return ( <> OpenShift cluster installation {progress >= 100 ? 'Installation complete!' : getCurrentStageName()} {/* Progress was getting announced on VoiceOver constantly - this helps avoid that */} {progress >= 100 ? 'Completed' : getTimeRemaining()} } />
{stages.map((stage) => ( { onExpandAccordion(stage.id); }} id={stage.id} > {renderStageIcon(stage)} {stage.name} {renderCodeBlock(stage)} ))}
); }; const VersionSelectorCard = () => { const [activeTabKey, setActiveTabKey] = useState(0); const [isCardSelected, setIsCardSelected] = useState(''); const [isExpanded, setIsExpanded] = useState(false); const id1 = '4.20'; const id2 = '4.19'; const id3 = '4.18'; const id4 = '4.17'; const onChange = (event: React.FormEvent) => { setIsCardSelected(event.currentTarget.id); }; const onToggleExpandableSection = (isExpanded: boolean) => { setIsExpanded(isExpanded); }; const handleTabClick = (_event: any, tabIndex: string | number) => { setActiveTabKey(tabIndex); }; const contentId = 'detached-expandable-section-content'; const toggleId = 'detached-expandable-section-toggle'; const generateTabContent = (title: string, subtitle: string) => (
{title}
{subtitle}
4.20.0-ec.3 Developer preview • Not for production 4.19.2 Newest features • 18-month support • Recommended 4.18.19 Previous stable • Full support 4.17.34 Maintenance support phase {isExpanded ? 'Hide older versions' : 'Show older versions'}
); return ( Single arch } > {generateTabContent('x86_64 Intel/AMD only', 'Standard deployments • Most common choice')} Multi arch } > {generateTabContent('Multi arch', 'Standard deployments')} ); }; const DownloadCard = () => ( Your discovery ISO is ready To begin adding hosts to your bare metal cluster, you first need to boot them with the generated Discovery ISO. This allows the installation program to see and manage your hardware. 1.2 GB • Expires in 24 hours Next step: After downloading, boot your bare metal hosts from this ISO image. ); export const UserMessageWithExtraContent: FunctionComponent = () => ( <> , afterMainContent: , endContent: }} /> }} /> }} /> }} /> );