src: Rename "V2" folders to just Wizard

This replaces all occurences of "CreateImageWizardV2" with just "CreateImageWizard" as it is the only version now.
This commit is contained in:
regexowl 2024-07-16 17:10:37 +02:00 committed by Ondřej Ezr
parent b1e5a8c7c6
commit 4fb37c187e
93 changed files with 20 additions and 22 deletions

View file

@ -0,0 +1,60 @@
import React, { ReactElement, useState } from 'react';
import { FormGroup } from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import { ARCHS } from '../../../../constants';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import { ImageRequest } from '../../../../store/imageBuilderApi';
import {
changeArchitecture,
selectArchitecture,
} from '../../../../store/wizardSlice';
const ArchSelect = () => {
const arch = useAppSelector(selectArchitecture);
const dispatch = useAppDispatch();
const [isOpen, setIsOpen] = useState(false);
const setArch = (
_event: React.MouseEvent,
selection: ImageRequest['architecture']
) => {
dispatch(changeArchitecture(selection));
setIsOpen(false);
};
const setSelectOptions = () => {
const options: ReactElement[] = [];
ARCHS.forEach((arch) => {
options.push(
<SelectOption key={arch} value={arch}>
{arch}
</SelectOption>
);
});
return options;
};
return (
<FormGroup isRequired={true} label="Architecture">
<Select
ouiaId="arch_select"
variant={SelectVariant.single}
onToggle={() => setIsOpen(!isOpen)}
onSelect={setArch}
selections={arch}
isOpen={isOpen}
>
{setSelectOptions()}
</Select>
</FormGroup>
);
};
export default ArchSelect;

View file

@ -0,0 +1,46 @@
import React from 'react';
import { Alert, Button } from '@patternfly/react-core';
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
import { DEVELOPERS_URL } from '../../../../constants';
const DeveloperProgramButton = () => {
return (
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href={DEVELOPERS_URL}
>
Red Hat Developer Program
</Button>
);
};
const CentOSAcknowledgement = () => {
return (
<Alert
variant="info"
isPlain
isInline
title={
<>
CentOS Stream builds are intended for the development of future
versions of RHEL and are not supported for production workloads or
other use cases.
</>
}
>
<p>
Join the <DeveloperProgramButton /> to learn about paid and no-cost RHEL
subscription options.
</p>
</Alert>
);
};
export default CentOSAcknowledgement;

View file

@ -0,0 +1,160 @@
import React, { useState } from 'react';
import {
Button,
ExpandableSection,
FormGroup,
Panel,
PanelMain,
} from '@patternfly/react-core';
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
import { Chart, registerables } from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { Bar } from 'react-chartjs-2';
import {
RELEASE_LIFECYCLE_URL,
RHEL_8,
RHEL_8_FULL_SUPPORT,
RHEL_8_MAINTENANCE_SUPPORT,
RHEL_9_FULL_SUPPORT,
RHEL_9_MAINTENANCE_SUPPORT,
} from '../../../../constants';
import { useAppSelector } from '../../../../store/hooks';
import { selectDistribution } from '../../../../store/wizardSlice';
import 'chartjs-adapter-moment';
Chart.register(annotationPlugin);
Chart.register(...registerables);
const currentDate = new Date().toISOString();
export const chartMajorVersionCfg = {
data: {
labels: ['RHEL 9', 'RHEL 8'],
datasets: [
{
label: 'Full support',
backgroundColor: '#0066CC',
data: [
{
x: RHEL_9_FULL_SUPPORT,
y: 'RHEL 9',
},
{
x: RHEL_8_FULL_SUPPORT,
y: 'RHEL 8',
},
],
},
{
label: 'Maintenance support',
backgroundColor: '#8BC1F7',
data: [
{
x: RHEL_9_MAINTENANCE_SUPPORT,
y: 'RHEL 9',
},
{
x: RHEL_8_MAINTENANCE_SUPPORT,
y: 'RHEL 8',
},
],
},
],
},
options: {
indexAxis: 'y' as const,
scales: {
x: {
type: 'time' as const,
time: {
unit: 'year' as const,
},
min: '2019-01-01' as const,
max: '2033-01-01' as const,
},
y: {
stacked: true,
},
},
responsive: true,
maintainAspectRatio: false,
plugins: {
tooltip: {
enabled: false,
},
legend: {
position: 'bottom' as const,
},
annotation: {
annotations: {
today: {
type: 'line' as const,
xMin: currentDate,
xMax: currentDate,
borderColor: 'black',
borderWidth: 2,
borderDash: [8, 2],
},
},
},
},
},
};
export const MajorReleasesLifecyclesChart = () => {
return (
<Panel>
<PanelMain maxHeight="10rem">
<Bar
data-testid="release-lifecycle-chart"
options={chartMajorVersionCfg.options}
data={chartMajorVersionCfg.data}
/>
</PanelMain>
</Panel>
);
};
const ReleaseLifecycle = () => {
const release = useAppSelector(selectDistribution);
const [isExpanded, setIsExpanded] = useState(true);
const onToggle = (_event: React.MouseEvent, isExpanded: boolean) => {
setIsExpanded(isExpanded);
};
if (release === RHEL_8) {
return (
<ExpandableSection
toggleText={
isExpanded
? 'Hide information about release lifecycle'
: 'Show information about release lifecycle'
}
onToggle={onToggle}
isExpanded={isExpanded}
isIndented
>
<FormGroup label="Release lifecycle">
<MajorReleasesLifecyclesChart />
</FormGroup>
<br />
<Button
component="a"
target="_blank"
variant="link"
icon={<ExternalLinkAltIcon />}
iconPosition="right"
isInline
href={RELEASE_LIFECYCLE_URL}
>
View Red Hat Enterprise Linux Life Cycle dates
</Button>
</ExpandableSection>
);
}
};
export default ReleaseLifecycle;

View file

@ -0,0 +1,114 @@
import React, { ReactElement, useState } from 'react';
import { FormGroup } from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import {
RELEASES,
RHEL_8,
RHEL_8_FULL_SUPPORT,
RHEL_8_MAINTENANCE_SUPPORT,
RHEL_9,
RHEL_9_FULL_SUPPORT,
RHEL_9_MAINTENANCE_SUPPORT,
} from '../../../../constants';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import { Distributions } from '../../../../store/imageBuilderApi';
import {
changeDistribution,
selectDistribution,
} from '../../../../store/wizardSlice';
import isRhel from '../../../../Utilities/isRhel';
import { toMonthAndYear } from '../../../../Utilities/time';
const ReleaseSelect = () => {
// What the UI refers to as the "release" is referred to as the "distribution" in the API.
// The Redux store follows the API convention, and data read from or to the store will use
// the word "Distribution" instead of "Release".
const distribution = useAppSelector(selectDistribution);
const dispatch = useAppDispatch();
const [isOpen, setIsOpen] = useState(false);
const [showDevelopmentOptions, setShowDevelopmentOptions] = useState(false);
const handleSelect = (_event: React.MouseEvent, selection: Distributions) => {
dispatch(changeDistribution(selection));
setIsOpen(false);
};
const handleExpand = () => {
setShowDevelopmentOptions(true);
};
const setDescription = (key: Distributions) => {
let fullSupportEnd = '';
let maintenanceSupportEnd = '';
if (key === RHEL_8) {
fullSupportEnd = toMonthAndYear(RHEL_8_FULL_SUPPORT[1]);
maintenanceSupportEnd = toMonthAndYear(RHEL_8_MAINTENANCE_SUPPORT[1]);
}
if (key === RHEL_9) {
fullSupportEnd = toMonthAndYear(RHEL_9_FULL_SUPPORT[1]);
maintenanceSupportEnd = toMonthAndYear(RHEL_9_MAINTENANCE_SUPPORT[1]);
}
if (isRhel(key)) {
return `Full support ends: ${fullSupportEnd} | Maintenance support ends: ${maintenanceSupportEnd}`;
}
};
const setSelectOptions = () => {
const options: ReactElement[] = [];
const filteredRhel = new Map(
[...RELEASES].filter(([key]) => {
// Only show non-RHEL distros if expanded
if (showDevelopmentOptions) {
return true;
}
return isRhel(key);
})
);
filteredRhel.forEach((value, key) => {
options.push(
<SelectOption
key={value}
value={key}
description={setDescription(key as Distributions)}
>
{RELEASES.get(key)}
</SelectOption>
);
});
return options;
};
return (
<FormGroup isRequired={true} label="Release">
<Select
ouiaId="release_select"
variant={SelectVariant.single}
onToggle={() => setIsOpen(!isOpen)}
onSelect={handleSelect}
selections={RELEASES.get(distribution)}
isOpen={isOpen}
{...(!showDevelopmentOptions && {
loadingVariant: {
text: 'Show options for further development of RHEL',
onClick: handleExpand,
},
})}
>
{setSelectOptions()}
</Select>
</FormGroup>
);
};
export default ReleaseSelect;

View file

@ -0,0 +1,342 @@
import React, { useState } from 'react';
import {
Button,
Checkbox,
FormGroup,
Popover,
Radio,
Text,
TextContent,
TextVariants,
Tile,
} from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';
import { useAppSelector, useAppDispatch } from '../../../../store/hooks';
import {
ImageTypes,
useGetArchitecturesQuery,
} from '../../../../store/imageBuilderApi';
import { provisioningApi } from '../../../../store/provisioningApi';
import {
addImageType,
reinitializeAws,
reinitializeAzure,
reinitializeGcp,
removeImageType,
selectArchitecture,
selectDistribution,
selectImageTypes,
} from '../../../../store/wizardSlice';
import { useGetEnvironment } from '../../../../Utilities/useGetEnvironment';
const TargetEnvironment = () => {
const arch = useAppSelector(selectArchitecture);
const environments = useAppSelector(selectImageTypes);
const distribution = useAppSelector(selectDistribution);
const { data } = useGetArchitecturesQuery({
distribution: distribution,
});
// TODO: Handle isFetching state (add skeletons)
// TODO: Handle isError state (very unlikely...)
const [hasVSphere, setHasVSphere] = useState(false);
const dispatch = useAppDispatch();
const prefetchSources = provisioningApi.usePrefetch('getSourceList');
const { isBeta } = useGetEnvironment();
const supportedEnvironments = data?.find(
(elem) => elem.arch === arch
)?.image_types;
const handleToggleEnvironment = (environment: ImageTypes) => {
if (environments.includes(environment)) {
switch (environment) {
case 'aws':
dispatch(reinitializeAws());
break;
case 'azure':
dispatch(reinitializeAzure());
break;
case 'gcp':
dispatch(reinitializeGcp());
}
dispatch(removeImageType(environment));
} else {
dispatch(addImageType(environment));
}
};
return (
<FormGroup
isRequired={true}
label="Select target environments"
data-testid="target-select"
>
<FormGroup
label={<Text component={TextVariants.small}>Public cloud</Text>}
data-testid="target-public"
>
<div className="tiles">
{supportedEnvironments?.includes('aws') && (
<Tile
className="tile pf-u-mr-sm"
data-testid="upload-aws"
title="Amazon Web Services"
icon={
<img
className="provider-icon"
src={'/apps/frontend-assets/partners-icons/aws.svg'}
alt="Amazon Web Services logo"
/>
}
onClick={() => {
handleToggleEnvironment('aws');
}}
onMouseEnter={() => prefetchSources({ provider: 'aws' })}
isSelected={environments.includes('aws')}
isStacked
isDisplayLarge
/>
)}
{supportedEnvironments?.includes('gcp') && (
<Tile
className="tile pf-u-mr-sm"
data-testid="upload-google"
title="Google Cloud Platform"
icon={
<img
className="provider-icon"
src={
'/apps/frontend-assets/partners-icons/google-cloud-short.svg'
}
alt="Google Cloud Platform logo"
/>
}
onClick={() => {
handleToggleEnvironment('gcp');
}}
isSelected={environments.includes('gcp')}
onMouseEnter={() => prefetchSources({ provider: 'gcp' })}
isStacked
isDisplayLarge
/>
)}
{supportedEnvironments?.includes('azure') && (
<Tile
className="tile pf-u-mr-sm"
data-testid="upload-azure"
title="Microsoft Azure"
icon={
<img
className="provider-icon"
src={
'/apps/frontend-assets/partners-icons/microsoft-azure-short.svg'
}
alt="Microsoft Azure logo"
/>
}
onClick={() => {
handleToggleEnvironment('azure');
}}
onMouseEnter={() => prefetchSources({ provider: 'azure' })}
isSelected={environments.includes('azure')}
isStacked
isDisplayLarge
/>
)}
{supportedEnvironments?.includes('oci') && (
<Tile
className="tile pf-u-mr-sm"
data-testid="upload-oci"
title="Oracle Cloud Infrastructure"
icon={
<img
className="provider-icon"
src={'/apps/frontend-assets/partners-icons/oracle-short.svg'}
alt="Oracle Cloud Infrastructure logo"
/>
}
onClick={() => {
handleToggleEnvironment('oci');
}}
isSelected={environments.includes('oci')}
isStacked
isDisplayLarge
/>
)}
</div>
</FormGroup>
{supportedEnvironments?.includes('vsphere') && (
<>
<FormGroup
label={<Text component={TextVariants.small}>Private cloud</Text>}
className="pf-u-mt-sm"
data-testid="target-private"
>
<Checkbox
label="VMware vSphere"
isChecked={
environments.includes('vsphere') ||
environments.includes('vsphere-ova')
}
onChange={() => {
setHasVSphere(!hasVSphere);
handleToggleEnvironment('vsphere-ova');
}}
aria-label="VMware checkbox"
id="checkbox-vmware"
name="VMware"
data-testid="checkbox-vmware"
/>
</FormGroup>
<FormGroup
className="pf-u-mt-sm pf-u-mb-sm pf-u-ml-xl"
data-testid="target-private-vsphere-radio"
>
{supportedEnvironments?.includes('vsphere-ova') && (
<Radio
name="vsphere-radio"
aria-label="VMware vSphere radio button OVA"
id="vsphere-radio-ova"
label={
<>
Open virtualization format (.ova)
<Popover
maxWidth="30rem"
position="right"
bodyContent={
<TextContent>
<Text>
An OVA file is a virtual appliance used by
virtualization platforms such as VMware vSphere. It
is a package that contains files used to describe a
virtual machine, which includes a VMDK image, OVF
descriptor file and a manifest file.
</Text>
</TextContent>
}
>
<Button
className="pf-u-pl-sm pf-u-pt-0 pf-u-pb-0"
variant="plain"
aria-label="About OpenSCAP"
isInline
>
<HelpIcon />
</Button>
</Popover>
</>
}
onChange={() => {
handleToggleEnvironment('vsphere-ova');
handleToggleEnvironment('vsphere');
}}
isChecked={environments.includes('vsphere-ova')}
isDisabled={
!(
environments.includes('vsphere') ||
environments.includes('vsphere-ova')
)
}
/>
)}
<Radio
className="pf-u-mt-sm"
name="vsphere-radio"
aria-label="VMware vSphere radio button VMDK"
id="vsphere-radio-vmdk"
label={
<>
Virtual disk (.vmdk)
<Popover
maxWidth="30rem"
position="right"
bodyContent={
<TextContent>
<Text>
A VMDK file is a virtual disk that stores the contents
of a virtual machine. This disk has to be imported
into vSphere using govc import.vmdk, use the OVA
version when using the vSphere UI.
</Text>
</TextContent>
}
>
<Button
className="pf-u-pl-sm pf-u-pt-0 pf-u-pb-0"
variant="plain"
aria-label="About OpenSCAP"
isInline
>
<HelpIcon />
</Button>
</Popover>
</>
}
onChange={() => {
handleToggleEnvironment('vsphere-ova');
handleToggleEnvironment('vsphere');
}}
isChecked={environments.includes('vsphere')}
isDisabled={
!(
environments.includes('vsphere') ||
environments.includes('vsphere-ova')
)
}
/>
</FormGroup>
</>
)}
<FormGroup
label={<Text component={TextVariants.small}>Other</Text>}
data-testid="target-other"
>
{supportedEnvironments?.includes('guest-image') && (
<Checkbox
label="Virtualization - Guest image (.qcow2)"
isChecked={environments.includes('guest-image')}
onChange={() => {
handleToggleEnvironment('guest-image');
}}
aria-label="Virtualization guest image checkbox"
id="checkbox-guest-image"
name="Virtualization guest image"
data-testid="checkbox-guest-image"
/>
)}
{supportedEnvironments?.includes('image-installer') && (
<Checkbox
label="Bare metal - Installer (.iso)"
isChecked={environments.includes('image-installer')}
onChange={() => {
handleToggleEnvironment('image-installer');
}}
aria-label="Bare metal installer checkbox"
id="checkbox-image-installer"
name="Bare metal installer"
data-testid="checkbox-image-installer"
/>
)}
{supportedEnvironments?.includes('wsl') && isBeta() && (
<Checkbox
label="WSL - Windows Subsystem for Linux (.tar.gz)"
isChecked={environments.includes('wsl')}
onChange={() => {
handleToggleEnvironment('wsl');
}}
aria-label="windows subsystem for linux checkbox"
id="checkbox-wsl"
name="WSL"
data-testid="checkbox-wsl"
/>
)}
</FormGroup>
</FormGroup>
);
};
export default TargetEnvironment;

View file

@ -0,0 +1,38 @@
import React from 'react';
import { Text, Form, Title } from '@patternfly/react-core';
import ArchSelect from './ArchSelect';
import CentOSAcknowledgement from './CentOSAcknowledgement';
import ReleaseLifecycle from './ReleaseLifecycle';
import ReleaseSelect from './ReleaseSelect';
import TargetEnvironment from './TargetEnvironment';
import { useAppSelector } from '../../../../store/hooks';
import { selectDistribution } from '../../../../store/wizardSlice';
import DocumentationButton from '../../../sharedComponents/DocumentationButton';
const ImageOutputStep = () => {
const distribution = useAppSelector(selectDistribution);
return (
<Form>
<Title headingLevel="h1" size="xl">
Image output
</Title>
<Text>
Images enables you to create customized blueprints, create custom images
from the blueprints, and push them to target environments
<br />
<DocumentationButton />
</Text>
<ReleaseSelect />
{distribution.match('centos-*') && <CentOSAcknowledgement />}
<ReleaseLifecycle />
<ArchSelect />
<TargetEnvironment />
</Form>
);
};
export default ImageOutputStep;