import React, { useEffect, useMemo } from 'react'; import { Alert, Button, Popover, Content, ContentVariants, FormGroup, CodeBlock, CodeBlockCode, } from '@patternfly/react-core'; import { ExclamationTriangleIcon } from '@patternfly/react-icons'; import ActivationKeyInformation from './../Registration/ActivationKeyInformation'; import { PackagesTable, RepositoriesTable, SnapshotTable, } from './ReviewStepTables'; import { FSReviewTable } from './ReviewStepTables'; import { FEDORA_RELEASES, ON_PREM_RELEASES, RELEASES, RHEL_8, RHEL_8_FULL_SUPPORT, RHEL_8_MAINTENANCE_SUPPORT, RHEL_9, targetOptions, UNIT_GIB, } from '../../../../constants'; import { useListSnapshotsByDateMutation, useGetTemplateQuery, } from '../../../../store/contentSourcesApi'; import { useAppSelector } from '../../../../store/hooks'; import { useGetSourceListQuery } from '../../../../store/provisioningApi'; import { useShowActivationKeyQuery } from '../../../../store/rhsmApi'; import { selectActivationKey, selectArchitecture, selectAwsAccountId, selectAwsShareMethod, selectAzureShareMethod, selectAzureSource, selectAzureResourceGroup, selectAzureSubscriptionId, selectAzureTenantId, selectAwsSourceId, selectBlueprintDescription, selectBlueprintName, selectCustomRepositories, selectDistribution, selectGcpAccountType, selectGcpEmail, selectGcpShareMethod, selectPackages, selectGroups, selectRegistrationType, selectFileSystemConfigurationType, selectRecommendedRepositories, selectSnapshotDate, selectUseLatest, selectPartitions, selectFirstBootScript, selectTimezone, selectNtpServers, selectLanguages, selectKeyboard, selectHostname, selectKernel, selectFirewall, selectServices, selectUsers, selectTemplate, selectRedHatRepositories, } from '../../../../store/wizardSlice'; import { toMonthAndYear, yyyyMMddFormat } from '../../../../Utilities/time'; import { useGetEnvironment } from '../../../../Utilities/useGetEnvironment'; import { getConversionFactor, MinimumSizePopover, Partition, } from '../FileSystem/FileSystemTable'; import { MajorReleasesLifecyclesChart } from '../ImageOutput/ReleaseLifecycle'; import OscapProfileInformation from '../Oscap/components/OscapProfileInformation'; import PopoverActivation from '../Registration/components/PopoverActivation'; const ExpirationWarning = () => { return (
Expires 14 days after creation
); }; export const ImageOutputList = () => { const distribution = useAppSelector(selectDistribution); const arch = useAppSelector(selectArchitecture); const { isFedoraEnv } = useGetEnvironment(); const releases = isFedoraEnv ? FEDORA_RELEASES : process.env.IS_ON_PREMISE ? ON_PREM_RELEASES : RELEASES; return ( {distribution === RHEL_8 && ( <> {RELEASES.get(distribution)} will be supported through{' '} {toMonthAndYear(RHEL_8_FULL_SUPPORT[1])}, with optional ELS support through {toMonthAndYear(RHEL_8_MAINTENANCE_SUPPORT[1])}. Consider building an image with {RELEASES.get(RHEL_9)} to extend the support period.
)} Release {releases.get(distribution)} Architecture {arch}
); }; export const FSCList = () => { const fileSystemConfigurationType = useAppSelector( selectFileSystemConfigurationType ); const partitions = useAppSelector(selectPartitions); return ( Configuration type {fileSystemConfigurationType === 'manual' ? 'Manual' : 'Automatic'} {fileSystemConfigurationType === 'manual' && ( <> {' '} } > )} {fileSystemConfigurationType === 'manual' && ( <> Image size (minimum) )} ); }; type MinSizeProps = { partitions: Partition[]; }; export const MinSize = ({ partitions }: MinSizeProps) => { let minSize = ''; if (partitions) { let size = 0; for (const partition of partitions) { size += Number(partition.min_size) * getConversionFactor(partition.unit); } size = Number((size / UNIT_GIB).toFixed(1)); if (size < 1) { minSize = `Less than 1 GiB`; } else { minSize = `${size} GiB`; } } return {minSize} ; }; export const TargetEnvAWSList = () => { const { isSuccess } = useGetSourceListQuery({ provider: 'aws', }); const awsAccountId = useAppSelector(selectAwsAccountId); const awsShareMethod = useAppSelector(selectAwsShareMethod); const sourceId = useAppSelector(selectAwsSourceId); const { source } = useGetSourceListQuery( { provider: 'aws', }, { selectFromResult: ({ data }) => ({ source: data?.data?.find((source) => source.id === sourceId), }), } ); return ( {targetOptions.aws} Image type Red Hat hosted image
Shared to account {awsAccountId} {awsShareMethod === 'sources' ? 'Source' : null} {isSuccess && awsShareMethod === 'sources' ? source?.name : null} Default region us-east-1
); }; export const TargetEnvGCPList = () => { const accountType = useAppSelector(selectGcpAccountType); const sharedMethod = useAppSelector(selectGcpShareMethod); const email = useAppSelector(selectGcpEmail); return ( {targetOptions.gcp} Image type Red Hat hosted image
<> {sharedMethod === 'withInsights' ? ( <> Shared with Red Hat Insights only
) : ( <> Account type {accountType === 'group' ? 'Google group' : accountType === 'serviceAccount' ? 'Service account' : accountType === 'user' ? 'Google account' : 'Domain'} {accountType === 'domain' ? 'Domain' : 'Principal'} {email || accountType} )}
); }; export const TargetEnvAzureList = () => { const { data: rawAzureSources, isSuccess: isSuccessAzureSources } = useGetSourceListQuery({ provider: 'azure' }); const shareMethod = useAppSelector(selectAzureShareMethod); const tenantId = useAppSelector(selectAzureTenantId); const azureSource = useAppSelector(selectAzureSource); const azureResourceGroup = useAppSelector(selectAzureResourceGroup); const subscriptionId = useAppSelector(selectAzureSubscriptionId); return ( {targetOptions.azure} Image type Red Hat hosted image
{shareMethod === 'sources' && isSuccessAzureSources && ( <> Azure Source { rawAzureSources?.data?.find( (source) => source.id === azureSource )?.name } )} {shareMethod === 'manual' && ( <> Azure tenant ID {tenantId} Subscription ID {subscriptionId} )} Resource group {azureResourceGroup}
); }; export const TargetEnvOciList = () => { return ( {targetOptions.oci} Object Storage URL The URL for the built image will be ready to copy ); }; export const TargetEnvOtherList = () => { return ( <> Image type Built image will be available for download ); }; export const ContentList = () => { const customRepositories = useAppSelector(selectCustomRepositories); const packages = useAppSelector(selectPackages); const groups = useAppSelector(selectGroups); const recommendedRepositories = useAppSelector(selectRecommendedRepositories); const snapshotDate = useAppSelector(selectSnapshotDate); const useLatest = useAppSelector(selectUseLatest); const template = useAppSelector(selectTemplate); const redHatRepositories = useAppSelector(selectRedHatRepositories); const customAndRecommendedRepositoryUUIDS = useMemo( () => [ ...customRepositories.map(({ id }) => id), ...recommendedRepositories.map(({ uuid }) => uuid), ] as string[], [customRepositories, recommendedRepositories] ); const [listSnapshotsByDate, { data, isSuccess, isLoading, isError }] = useListSnapshotsByDateMutation(); useEffect(() => { if (!snapshotDate && !useLatest) return; listSnapshotsByDate({ apiListSnapshotByDateRequest: { repository_uuids: customAndRecommendedRepositoryUUIDS, date: useLatest ? yyyyMMddFormat(new Date()) + 'T00:00:00Z' : snapshotDate, }, }); }, [ customAndRecommendedRepositoryUUIDS, listSnapshotsByDate, snapshotDate, useLatest, ]); const duplicatePackages = packages.filter( (item, index) => packages.indexOf(item) !== index ); const noRepositoriesSelected = customAndRecommendedRepositoryUUIDS.length === 0 && redHatRepositories.length === 0; const hasSnapshotDateAfter = data?.data?.some(({ is_after }) => is_after); const { data: templateData, isLoading: isTemplateLoading } = useGetTemplateQuery( { uuid: template, }, { refetchOnMountOrArgChange: true, skip: template === '' } ); const snapshottingText = useMemo(() => { switch (true) { case isLoading || isTemplateLoading: return ''; case useLatest: return 'Use latest'; case !!snapshotDate: return `State as of ${yyyyMMddFormat(new Date(snapshotDate))}`; case !!template: return `Use a content template: ${templateData?.name}`; default: return ''; } }, [isLoading, isTemplateLoading, useLatest, snapshotDate, template]); return ( <> <> Repeatable build } > {!useLatest && !isLoading && isSuccess && hasSnapshotDateAfter ? ( ) : ( '' )} Custom repositories {customRepositories?.length + recommendedRepositories.length > 0 ? ( } > ) : ( 0 )} Additional packages {packages?.length > 0 || groups?.length > 0 ? ( } > ) : ( 0 )} {duplicatePackages.length > 0 && ( Some of the packages added to this image belong to multiple added repositories. We can not guarantee which repository the package will come from. )} ); }; export const RegisterLaterList = () => { return ( Registration type Register the system later ); }; export const RegisterSatelliteList = () => { return ( Register Satellite Enabled ); }; export const RegisterNowList = () => { const activationKey = useAppSelector(selectActivationKey); const registrationType = useAppSelector(selectRegistrationType); const { isError } = useShowActivationKeyQuery( // @ts-ignore type of 'activationKey' might not be strictly compatible with the expected type for 'name'. { name: activationKey }, { skip: !activationKey, } ); return ( <> Registration type {registrationType?.startsWith('register-now') && ( Register with Red Hat Subscription Manager (RHSM)
)} {(registrationType === 'register-now-insights' || registrationType === 'register-now-rhc') && ( Connect to Red Hat Insights
)} {registrationType === 'register-now-rhc' && ( Use remote host configuration (rhc) utility
)}
Activation key
{isError && ( Information about the activation key cannot be loaded. Please check the key was not removed and try again later. )} ); }; export const DetailsList = () => { const blueprintName = useAppSelector(selectBlueprintName); const blueprintDescription = useAppSelector(selectBlueprintDescription); return ( {blueprintName && ( <> Blueprint name {blueprintName} )} {blueprintDescription && ( <> Description {blueprintDescription} )} ); }; export const OscapList = () => { return ; }; export const TimezoneList = () => { const timezone = useAppSelector(selectTimezone); const ntpServers = useAppSelector(selectNtpServers); return ( Timezone {timezone ? timezone : 'None'} NTP servers {ntpServers && ntpServers.length > 0 ? ntpServers.join(', ') : 'None'} ); }; export const UsersList = () => { const users = useAppSelector(selectUsers); return ( {users.map((user) => ( Username {user.name ? user.name : 'None'} Password {user.password || user.hasPassword ? '●'.repeat(8) : 'None'} SSH key {user.ssh_key ? user.ssh_key : 'None'} Administrator {user.isAdministrator ? 'True' : 'False'} ))} ); }; export const LocaleList = () => { const languages = useAppSelector(selectLanguages); const keyboard = useAppSelector(selectKeyboard); return ( Languages {languages && languages.length > 0 ? languages.join(', ') : 'None'} Keyboard {keyboard ? keyboard : 'None'} ); }; export const HostnameList = () => { const hostname = useAppSelector(selectHostname); return ( Hostname {hostname ? hostname : 'None'} ); }; export const KernelList = () => { const kernel = useAppSelector(selectKernel); return ( Name {kernel.name ? kernel.name : 'None'} Append {kernel.append.length > 0 ? ( {kernel.append.join(' ')} ) : ( 'None' )} ); }; export const FirewallList = () => { const firewall = useAppSelector(selectFirewall); return ( Ports {firewall.ports.length > 0 ? ( {firewall.ports.join(' ')} ) : ( 'None' )} Disabled services {firewall.services.disabled.length > 0 ? ( {firewall.services.disabled.join(' ')} ) : ( 'None' )} Enabled services {firewall.services.enabled.length > 0 ? ( {firewall.services.enabled.join(' ')} ) : ( 'None' )} ); }; export const ServicesList = () => { const services = useAppSelector(selectServices); return ( Disabled {services.disabled.length > 0 ? ( {services.disabled.join(' ')} ) : ( 'None' )} Masked {services.masked.length > 0 ? ( {services.masked.join(' ')} ) : ( 'None' )} Enabled {services.enabled.length > 0 ? ( {services.enabled.join(' ')} ) : ( 'None' )} ); }; export const FirstBootList = () => { const isFirstbootEnabled = !!useAppSelector(selectFirstBootScript); return ( First boot script {isFirstbootEnabled ? 'Enabled' : 'Disabled'} ); };